Missing Numbers (ranges) in Multiple Columns

  • I see lots of examples where one needs to parse a csv list to find the gaps of missing values or a single column integer and its missing range of values. I need to find the gaps of missing numbers in two 24 hour time-stamp (Hour) columns. Two columns, one row, like:

    DECLARE @TestTVTABLE

    (

    DepartmentNVARCHAR(100),

    ReceiptNVARCHAR(100),

    StartDateDATETIME,

    EndDateDATETIME,

    HourStartINT,

    HourCompleteINT

    )

    INSERT INTO @TestTV VALUES('GM','BFI110429083349','04/29/2011','04/29/2011',6,8)

    INSERT INTO @TestTV VALUES('Grocery','DWH110429032648','04/28/2011','04/29/2011',23,3)

    And then transform the data into another table variable like this:

    DECLARE @TestTVTABLE

    (

    DepartmentNVARCHAR(100),

    ReceiptNVARCHAR(100),

    StartDateDATETIME,

    EndDateDATETIME,

    HoursActiveINT

    )

    INSERT INTO @TestTV VALUES('GM','BFI110429083349','04/29/2011','04/29/2011',6)

    INSERT INTO @TestTV VALUES('GM','BFI110429083349','04/29/2011','04/29/2011',7)

    INSERT INTO @TestTV VALUES('GM','BFI110429083349','04/29/2011','04/29/2011',8)

    INSERT INTO @TestTV VALUES('Grocery','DWH110429032648','04/28/2011','04/29/2011',23)

    INSERT INTO @TestTV VALUES('Grocery','DWH110429032648','04/28/2011','04/29/2011',0)

    INSERT INTO @TestTV VALUES('Grocery','DWH110429032648','04/28/2011','04/29/2011',1)

    INSERT INTO @TestTV VALUES('Grocery','DWH110429032648','04/28/2011','04/29/2011',2)

    INSERT INTO @TestTV VALUES('Grocery','DWH110429032648','04/28/2011','04/29/2011',3)

    SELECT * FROM @TestTV

    Thanks.

  • Like so?

    ;

    WITH cte AS

    (

    SELECT Department,

    Receipt,

    StartDate,

    EndDate,

    HourStart,

    HourComplete,

    -- combine the hours into the appropriate date column, and get the difference in hours

    -- this way, if someone is on the clock > 1 day, it will still work!

    HourDiff = DATEDIFF(HOUR, DATEADD(HOUR, HourStart, StartDate), DATEADD(HOUR, HourComplete, EndDate))

    FROM @TestTV t1

    )

    SELECT t1.Department,

    t1.Receipt,

    t1.StartDate,

    t1.EndDate,

    -- add each incremental hour to the starting hour, show the remainder when divided by 24 (modulus)

    HoursActive = (t2.MyHour + t1.HourStart)%24

    FROM cte t1

    -- get each hour within the range

    CROSS APPLY (SELECT MyHour = DATEPART(HOUR, DATEADD(HOUR, N-1, t1.StartDate))

    FROM dbo.Tally

    WHERE N BETWEEN 1 AND t1.HourDiff+1) t2;

    Wayne
    Microsoft Certified Master: SQL Server 2008
    Author - SQL Server T-SQL Recipes


    If you can't explain to another person how the code that you're copying from the internet works, then DON'T USE IT on a production system! After all, you will be the one supporting it!
    Links:
    For better assistance in answering your questions
    Performance Problems
    Common date/time routines
    Understanding and Using APPLY Part 1 & Part 2

  • A slight variation from Wayne's Code:

    ; WITH Tens (N) AS

    (

    SELECT 1

    UNION ALL SELECT 1

    UNION ALL SELECT 1

    UNION ALL SELECT 1

    UNION ALL SELECT 1

    UNION ALL SELECT 1

    UNION ALL SELECT 1

    UNION ALL SELECT 1

    UNION ALL SELECT 1

    UNION ALL SELECT 1

    )

    , Hundreds (N) AS

    (

    SELECT T1.N FROM Tens T1 CROSS JOIN Tens T2

    )

    , Thousands (N) AS

    (

    SELECT T1.N FROM Hundreds T1 CROSS JOIN Hundreds T2

    )

    , NumbersTable(N) AS

    (

    SELECT 0

    UNION ALL

    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 0)) FROM Thousands

    ),

    DiffHours AS

    (

    SELECT Department , Receipt , StartDate , EndDate

    ,HourStart

    ,NumOfHours = DATEDIFF ( HH ,DATEADD ( HH , HourStart , StartDate) , DATEADD ( HH , HourComplete , EndDate) ) + 1

    FROM @TestTV

    )

    SELECT DF.Department , DF.Receipt , DF.StartDate , DF.EndDate

    , (( DF.HourStart + NT.N ) % 24 ) HoursActive

    FROM DiffHours DF

    CROSS JOIN NumbersTable NT

    WHERE DF.NumOfHours > NT.N

  • Or...

    SELECT

    TTV.Department,

    TTV.Receipt,

    TTV.StartDate,

    TTV.EndDate,

    DV.HoursActive

    FROM @TestTV AS TTV

    JOIN

    (

    SELECT DISTINCT

    V.HoursActive

    FROM

    (

    VALUES

    (00),(01),(02),(03),(04),(05),(06),(07),(08),(09),(10),(11),

    (12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23)

    ) AS V (HoursActive)

    ) AS DV ON

    (TTV.HourStart < TTV.HourComplete AND DV.HoursActive >= TTV.HourStart AND DV.HoursActive <= TTV.HourComplete)

    OR

    (TTV.HourStart > TTV.HourComplete AND (DV.HoursActive <= TTV.HourComplete OR DV.HoursActive >= TTV.HourStart));

  • Thank you all very much. A few different techniques, great stuff. Thanks again.

Viewing 5 posts - 1 through 4 (of 4 total)

You must be logged in to reply to this topic. Login to reply