• Lempster (1/29/2014)


    Jeff Moden (1/29/2014)


    Too bad because I finally learned how to copy'n'paste my SARGable solution correctly. :blush:

    Could you post your solution anyway Jeff?

    Regards

    Lempster

    Sure. With the understanding that such data should never be stored in a table and that it should be normalized as a real DATETIME column and a separate column for the "time of day slot" indicator, here's how to solve this problem in a SARGable fashion. For those that don't know, "SARGable" has come to basically mean "can do an Index Seek if the correct supporting index is available".

    --=============================================================================

    -- Create a larger test table with the appropriate index

    -- Only adding the appropriate index is a part of the solution

    --=============================================================================

    --DROP TABLE dbo.#DateTest

    GO

    --===== Create the table, as before

    CREATE TABLE dbo.#DateTest

    (

    FromDate varchar(9)

    ,ToDate varchar(9)

    )

    ;

    --===== Insert the original 4 rows in the test data

    INSERT INTO dbo.#DateTest

    SELECT '201401221','201401292' UNION ALL

    SELECT '201401092','201401161' UNION ALL

    SELECT NULL ,'201402282' UNION ALL

    SELECT '201401152',NULL

    ;

    GO

    --===== Insert another 16380 similar rows

    INSERT INTO #DateTest

    SELECT * FROM #DateTest

    GO 12

    --===== Add the expected index

    CREATE INDEX IX_#DateTest

    ON #DateTest (FromDate,ToDate)

    ;

    --=============================================================================

    -- Demonstrate the the current solution will NOT do an Index Seek

    -- and a method that will. The Index Seek is followed by a nice

    -- high performance range scan

    --=============================================================================

    --===== Setup the variable for @Today to make testing easy

    DECLARE @Today DATETIME

    SELECT @Today = GETDATE() --Or whatever

    ;

    --===== This CANNOT do an Index Seek because of the formulas

    -- on the FromDate and ToDate columns (non-SARGable).

    SELECT ISNULL(CAST(SUBSTRING(FromDate,1,8) AS int),19000101) AS FromDate

    ,ISNULL(CAST(SUBSTRING(ToDate,1,8) as int),99991231) AS ToDate

    FROM dbo.#DateTest

    WHERE ISNULL(SUBSTRING(FromDate,1,8),19000101) <= @Today

    AND ISNULL(SUBSTRING(ToDate,1,8),99991231) > @Today

    ;

    --===== This DOES do an Index Seek because there are no forumulas

    -- on the table columns in the WHERE clause (SARGable).

    SELECT FromDate = FromDate -- ISNULL(FromDate,'19000101')

    ,ToDate = ToDate -- ISNULL(ToDate ,'99991231')

    FROM dbo.#DateTest

    WHERE (FromDate <= CONVERT(CHAR(8),@Today ,112)+'9' OR FromDate IS NULL)

    AND (ToDate >= CONVERT(CHAR(8),@Today ,112)+'0' OR ToDate IS NULL)

    ;

    Notice the neither FromDate or ToDate is contained in a formula.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)