SQL中任意数量的时间系列的日期交集

时间:2016-02-20 02:30:27

标签: sql tsql sql-server-2012 time-series

如何在没有循环的情况下计算SQL中任意数量的时间序列的日期交集?

鉴于我有一个包含3列的表

  1. 的GroupId
  2. 开始日期
  3. 结束日期
  4. 每个GroupId

    有多行 - 所以每个GroupId有多个开始/结束日期(在一个组内没有重叠)

    我想要做的是查找所有组之间的所有相交日期 因此,如果第1组具有以下日期

    1/1/2001 - 1/31/2001
    3/31/2001 - 4/5/2001
    

    第2组有以下

    1/25/2001 - 5/1/2001
    

    第3组有以下

    1/22/2001 - 4/1/2001
    

    以上所有内容都在:

    1/25/2001 - 1/31/2001
    3/31/2001 - 1/4/2001
    

    我如何在SQL中执行此操作?以下是一个表中2个日期范围的逻辑,但我需要在一个表中的n个日期范围:

    SELECT 
        case 
            when t1.StartDate > t2.StartDate then t1.StartDate 
            else t2.StartDate 
        END as StartDate,
        CASE WHEN t1.EndDate < t2.EndDate THEN t1.EndDate
            ELSE t2.EndDate
        END as EndDate
    FROM Table1 t1
    JOIN Table1 t2 ON t1.StartDate <= t2.EndDate AND t1.EndDate >= t2.StartDate    
    

    (注意:作为一个额外的约束,我在linq to sql中这样做)

    提前致谢

1 个答案:

答案 0 :(得分:1)

您可以通过分离组中的日期并使用累计金额然后进行一些比较来完成此操作。在SQL Server 2012+中,它看起来像:

with g as (
      select groupid, start as dte, 1 as enters, 0 as exits
      from t
      union all
      select groupid, dateadd(day, 1, end), 0, 1
      from t
     ),
     gs as (
      select groupid, dte, sum(enters) as enters, sum(exits) as exits,
             sum(sum(enters)) over (order by dte) as cumeenters,
             sum(sum(exits)) over (order by dte) as cumexits
      from g
      group by dte, groupid
     )
select ne, nextdte
from (select gs.*, lead(dte) over (order by dte) as nextdte
      from gs
     ) gs
where cumeenters - cumeexits = (select count(distinct groupid) from t);

处理如下:

  • 第一个子查询将开始日期和结束日期分隔为单独的记录。
  • 第二个累积开始和结束以获得累积值。
  • where子句选择表示所有组的日期。

Here是SQL小提琴。