Merge overlapping date intervals

后端 未结 7 996
不知归路
不知归路 2020-11-27 16:16

Is there a better way of merging overlapping date intervals?
The solution I came up with is so simple that now I wonder if someone else has a better idea of how this cou

7条回答
  •  悲&欢浪女
    2020-11-27 16:45

    Here is a solution with just three simple scans. No CTEs, no recursion, no joins, no table updates in a loop, no "group by" — as a result, this solution should scale the best (I think). I think number of scans can be reduced to two, if min and max dates are known in advance; the logic itself just needs two scans — find gaps, applied twice.

    declare @datefrom datetime, @datethru datetime
    
    DECLARE @T TABLE (d1 DATETIME, d2 DATETIME)
    
    INSERT INTO @T (d1, d2)
    
    SELECT '2010-01-01','2010-03-31' 
    UNION SELECT '2010-03-01','2010-06-13' 
    UNION SELECT '2010-04-01','2010-05-31' 
    UNION SELECT '2010-06-15','2010-06-25' 
    UNION SELECT '2010-06-26','2010-07-10' 
    UNION SELECT '2010-08-01','2010-08-05' 
    UNION SELECT '2010-08-01','2010-08-09' 
    UNION SELECT '2010-08-02','2010-08-07' 
    UNION SELECT '2010-08-08','2010-08-08' 
    UNION SELECT '2010-08-09','2010-08-12' 
    UNION SELECT '2010-07-04','2010-08-16' 
    UNION SELECT '2010-11-01','2010-12-31' 
    
    select @datefrom = min(d1) - 1, @datethru = max(d2) + 1 from @t
    
    SELECT 
    StartDate, EndDate
    FROM
    (
        SELECT 
        MAX(EndDate) OVER (ORDER BY StartDate) + 1 StartDate,
        LEAD(StartDate ) OVER (ORDER BY StartDate) - 1 EndDate
        FROM
        (
            SELECT 
            StartDate, EndDate
            FROM
            (
                SELECT 
                MAX(EndDate) OVER (ORDER BY StartDate) + 1 StartDate,
                LEAD(StartDate) OVER (ORDER BY StartDate) - 1 EndDate 
                FROM 
                (
                    SELECT d1 StartDate, d2 EndDate from @T 
                    UNION ALL 
                    SELECT @datefrom StartDate, @datefrom EndDate 
                    UNION ALL 
                    SELECT @datethru StartDate, @datethru EndDate
                ) T
            ) T
            WHERE StartDate <= EndDate
            UNION ALL 
            SELECT @datefrom StartDate, @datefrom EndDate 
            UNION ALL 
            SELECT @datethru StartDate, @datethru EndDate
        ) T
    ) T
    WHERE StartDate <= EndDate
    

    The result is:

    StartDate   EndDate
    2010-01-01  2010-06-13
    2010-06-15  2010-08-16
    2010-11-01  2010-12-31
    

提交回复
热议问题