T-SQL - 重叠日期时间列的时间跨度

T-SQL - timespan by overlapping datetime columns

我想要相互重叠的日期范围的最大时间段,如果该时间段不与其他日期范围冲突,那么我希望它保持原样。

我有这个table:

CREATE TABLE [dbo].[table1]
(
    [id] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
    [StartDate] [datetime] NOT NULL,
    [EndDate] [datetime] NOT NULL
)

及其各自的值:

INSERT INTO [dbo].[table1]  
VALUES (CAST('2013-11-01 00:00:00.000' AS DateTime), CAST('2013-11-10 00:00:00.000' AS DateTime)),
       (CAST('2013-11-05 00:00:00.000' AS DateTime), CAST('2013-11-15 00:00:00.000' AS DateTime)),
       (CAST('2013-11-10 00:00:00.000' AS DateTime), CAST('2013-11-15 00:00:00.000' AS DateTime)),
       (CAST('2013-11-10 00:00:00.000' AS DateTime), CAST('2013-11-25 00:00:00.000' AS DateTime)),
       (CAST('2013-11-26 00:00:00.000' AS DateTime), CAST('2013-11-29 00:00:00.000' AS DateTime))

预期结果是:

ID    StartDate                  EndDate
--------------------------------------------------------
1     2013-11-01 00:00:00.000    2013-11-25 00:00:00.000
2     2013-11-26 00:00:00.000    2013-11-29 00:00:00.000

提前致谢。

// 编辑 1:谢谢。

有效,但在同一 table

中有一个新的中断问题
INSERT INTO [dbo].[table1]  
VALUES (CAST('2018-05-03 08:30:00.000' AS DateTime), CAST('2018-05-03 08:45:00.000' AS DateTime)),
       (CAST('2018-05-03 08:45:00.000' AS DateTime), CAST('2018-05-03 09:30:00.000' AS DateTime)),
       (CAST('2018-05-03 08:45:00.000' AS DateTime), CAST('2018-05-03 11:30:00.000' AS DateTime)),
       (CAST('2018-05-03 12:45:00.000' AS DateTime), CAST('2018-05-03 13:00:00.000' AS DateTime)),
       (CAST('2018-05-03 14:00:00.000' AS DateTime), CAST('2018-05-03 15:45:00.000' AS DateTime)),
       (CAST('2018-05-03 14:15:00.000' AS DateTime), CAST('2018-05-03 15:30:00.000' AS DateTime))

预期结果是:

ID    StartDate                  EndDate
--------------------------------------------------------
1     2018-05-03 08:30:00.000    2018-05-03 11:30:00.000
2     2018-05-03 12:45:00.000    2018-05-03 13:00:00.000
3     2018-05-03 14:00:00.000    2018-05-03 15:45:00.000

这是间隙和孤岛问题的一种形式。

在这种情况下,exists和累积总和以及group by是解决问题的途径:

select row_number() over (order by min(startdate)),
       min(startdate), max(enddate)
from (select t1.*, sum(isstart) over (order by startdate) as grp
      from (select t1.*,
                   (case when exists (select 1
                                      from table1 tt1
                                      where tt1.startdate <= t1.enddate and tt1.enddate >= t1.startdate and tt1.id <> t1.id
                                     )
                         then 0 else 1
                    end) as isstart
            from table1 t1
           ) t1
     ) t1
group by grp;

非常相似的答案,但使用索引和窗口函数使间隙和孤岛分析更便宜(更快)。

http://sqlfiddle.com/#!18/f19569/3

SELECT
  ROW_NUMBER() OVER (ORDER BY MIN(StartDate)),
  MIN(StartDate),
  MAX(EndDate)
from
(
  SELECT
    *,
    SUM(CASE WHEN PrecedingEndDate >= StartDate THEN 0 ELSE 1 END)
      OVER (ORDER BY StartDate, EndDate)
        AS GroupID
  FROM
  (
    SELECT
      *,
      MAX(EndDate)
        OVER (ORDER BY StartDate, EndDate
                  ROWS BETWEEN UNBOUNDED PRECEDING
                           AND 1 PRECEDING
             )
               AS PrecedingEndDate
    FROM
      Table1
  )
    look_back
)
  grouped
GROUP BY
  GroupID