我需要查找第一个 StartDate 和最后一个 EndDate 之间超出日期范围 20 天或以上的所有 ID。
一个 ID 有多个开始日期和结束日期。在以下示例中,Id 1 有两个间隔,每个间隔都小于 20 天。应将其视为从 10/01/2012 到 10/30/2014 的一个范围,没有任何间隙。
1 10/01/2012 02/01/2013
1 01/01/2013 01/31/2013
1 02/10/2013 03/31/2013
1 04/15/2013 10/30/2014
ID 2 的结束日期 01/30/2013 和开始日期 05/01/2013 之间的间隔超过 20 天,因此必须由查询捕获。
2 01/01/2013 01/30/2013
2 05/01/2013 06/30/2014
2 07/01/2013 02/01/2014
Id 3 应被视为从 01/01/2012 到 06/01/2014 的一个范围,没有任何间隙。应忽略结束日期 02/28/2013 和开始日期 07/01/2013 之间的差距,因为从 01/01/2012 到 01/01/2014 的范围涵盖了该差距。
3 01/01/2012 01/01/2014
3 01/01/2013 02/28/2013
3 07/01/2013 06/01/2014
光标可以做到这一点,但它的工作速度非常慢并且 Not Acceptable 。
SQL fiddle :http://sqlfiddle.com/#!3/27e3f/2/0
最佳答案
使用你的 fiddle 模式,试试这个:
;WITH naivegaps AS
(
SELECT ROW_NUMBER() OVER (ORDER BY id, startdate, MAX(dr1.enddate)) AS rn,
dr1.Id, dr1.startdate, MAX(dr1.enddate) as enddate
FROM dateranges dr1
GROUP BY dr1.Id, dr1.startdate
)
SELECT n1.id, n1.enddate as gap_start, n2.startdate AS gap_end,
datediff(dd, n1.enddate, n2.startdate) as gap_width, n3.*
FROM naivegaps n1
CROSS APPLY
(
SELECT TOP 1 nx.id, nx.startdate
FROM naivegaps nx
WHERE n1.id = nx.id AND nx.rn > n1.rn
ORDER BY nx.startdate
) n2
OUTER APPLY
(
SELECT TOP 1 nx.id, nx.enddate
FROM naivegaps nx
WHERE n1.id = nx.id AND nx.rn < n1.rn
ORDER BY nx.enddate DESC
) n3
WHERE datediff(dd, n1.enddate, n2.startdate) >= 20 AND (n3.enddate <= n1.enddate OR n3.enddate IS NULL)
顶部的 CTE 对以下检查的所有内容进行适当排序,并添加行号以方便排序检查。 CROSS APPLY
查找序列末尾与后续开头之间的所有间隙。 OUTER APPLY
检查完全包围相关间隙的范围(在 CROSS APPLY
中不会进行适当排序)
编辑:我将此解决方案的执行计划与 Joe Farrell 提供的递归 CTE 解决方案进行了比较。它们是明显不同的计划,但估计的效率非常接近(我的稍微好一点,大约 4%)。这可能会也可能不会转化为大型数据集的实际性能;我鼓励您测试这两种方法并使用最适合您的场景的方法。
关于sql - 查找开始/结束日期范围覆盖范围上限超过 20 天的 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24090227/