计算区间表的集合差

Rus*_*hta 5 sql-server datetime interval sql-server-2019

我经常遇到以下问题。我有两张间隔表。它们受日期限制(没有时间部分)。每个表中的间隔不重叠。

开始时间 结束时间
2015-01-03 2015-03-02
2015-03-05 2015-04-01
开始时间 结束时间
2015-01-07 2015-02-27
2015-03-01 2015-03-13
2016-01-01 2016-01-02

我想找到两个表的集合差异,即代表第一个表中而不是第二个表中的时间的间隔。

上面的虚拟示例所需的输出:

开始时间 结束时间
2015-01-03 2015-01-06
2015-02-28 2015-02-28
2015-03-14 2015-04-01

即,如果第一个表的日期在下面用黄色标记,并且第二个表的范围用框包围,我将寻找未装箱的黄色日期的连续范围。

在此输入图像描述

我目前将两端都视为包含间隔,并使用 DateTime 作为时间戳。我当前的方法是通过三重自连接(恶心)获取第二个表的补集,然后通过连接将结果与第一个表相交。不好玩。

有更好的方法吗?

Mar*_*ith 5

考虑到各种简化假设(只有日期并且表格内没有重叠的间隔),我可能会介意让事情变得简单。

首先创建一个辅助数字表(从零开始)

CREATE TABLE dbo.SmallNumbers
(
Number SMALLINT PRIMARY KEY
)

INSERT INTO dbo.SmallNumbers
SELECT TOP 32768 ROW_NUMBER() OVER (ORDER BY @@SPID)-1 AS Number
FROM sys.all_columns c1, sys.all_columns c2
Run Code Online (Sandbox Code Playgroud)

然后,下面的代码将范围扩展到其组成日期,用于EXCEPT查找差异以及间隙和岛屿技术来将范围缩小。由于每个日期只会出现一次,我们可能只会谈论扩展到每十年覆盖的几千个日期。

WITH UnmatchedDates(Date) AS
(
SELECT DATEADD(DAY,N.Number, StartTs)
FROM Table1
JOIN dbo.SmallNumbers N ON N.Number <= DATEDIFF(DAY, StartTs, EndTs)
EXCEPT 
SELECT DATEADD(DAY,N.Number, StartTs)
FROM Table2
JOIN dbo.SmallNumbers N ON N.Number <= DATEDIFF(DAY, StartTs, EndTs)
),
UnmatchedDatesWithGrp(Date, Grp) AS
(
SELECT Date, 
       DATEDIFF(DAY, 0, Date) - ROW_NUMBER() OVER (ORDER BY Date)
FROM UnmatchedDates
)
SELECT StartTs = MIN(Date), 
         EndTs = MAX(Date)
FROM UnmatchedDatesWithGrp
GROUP BY Grp
Run Code Online (Sandbox Code Playgroud)