Search code examples
sqlsql-servertimeperiod

Intersection and consolidation of time periods in SQL


I want to achieve similar function that is available in Time Period Library for .NET, but in SQL.

First, I have a table with several rows with an Start Date and an End Date, and I want to consolidate them together like this:

Combination

Then with that result and another coming from a different table, I want to find out the intersection between the two of them, like this but only 2 inputs (find the periods that are present in both):

Intersection

Once I have the intersection is just summing up the time on it.

Here I provide a SQL Fiddle with the expected output with an example:

http://sqlfiddle.com/#!18/504fa/3


Solution

  • Sample data preparation

    CREATE TABLE TableToCombine
        ([IdDoc] int IDENTITY(1,1), [IdEmployee] int, [StartDate] datetime, [EndDate] datetime)
    ;
    
    INSERT INTO TableToCombine
        (IdEmployee, StartDate, EndDate)
    VALUES
        (1, '2018-01-01 06:00:00', '2018-01-01 14:00:00'),
        (2, '2018-01-01 11:00:00', '2018-01-01 19:00:00'),
        (3, '2018-01-01 20:00:00', '2018-01-02 03:00:00'),
        (1, '2018-01-02 06:00:00', '2018-01-02 14:00:00'),
        (2, '2018-01-02 11:00:00', '2018-01-02 19:00:00')
    ;
    
    CREATE TABLE TableToIntersect
        ([IdDoc] int IDENTITY(1,1), [OrderId] int, [StartDate] datetime, [EndDate] datetime)
    ;
    
    INSERT INTO TableToIntersect
        (OrderId, StartDate, EndDate)
    VALUES
        (1, '2018-01-01 09:00:00', '2018-01-02 12:00:00')
    ;
    

    Query:

    with ExpectedCombineOutput as (
        select
            grp, StartDate = min(StartDate), EndDate = max(EndDate)
        from (
            select
                *, sum(iif(cd between StartDate and EndDate, 0, 1))over(order by StartDate) grp
            from (
                select
                    *, lag(EndDate) over (order by IdDoc) cd
                from
                    TableToCombine
            ) t
        ) t
        group by grp
    )
    
    select 
        a.grp, StartDate = iif(a.StartDate < b.StartDate, b.StartDate, a.StartDate)
        , EndDate = iif(a.EndDate < b.EndDate, a.EndDate, b.EndDate)
    from
        ExpectedCombineOutput a
        join TableToIntersect b on a.StartDate <= b.EndDate and a.EndDate >= b.StartDate
    

    Intersecting time intervals are combined in CTE. And then joined with your intersectTable to find overlapping periods. Two periods overlap if a.StartDate < b.EndDate and a.EndDate > b.StartDate