如何在 SQL 中选择重叠的日期范围
Posted
技术标签:
【中文标题】如何在 SQL 中选择重叠的日期范围【英文标题】:How to select overlapping date ranges in SQL 【发布时间】:2018-04-14 21:50:24 【问题描述】:我有一个包含以下列的表格: sID、开始日期和结束日期
部分值如下:
1 1995-07-28 2003-07-20
1 2003-07-21 2010-05-04
1 2010-05-03 2010-05-03
2 1960-01-01 2011-03-01
2 2011-03-02 2012-03-13
2 2012-03-12 2012-10-21
2 2012-10-22 2012-11-08
3 2003-07-23 2010-05-02
我只想要结果中的第 2 行和第 3 行,因为它们是重叠的日期范围。
我试过这个,但它不会摆脱第一行。不知道哪里出错了?
select a.sID from table a
inner join table b
on a.sID = b.sID
and ((b.start_date between a.start_date and a.end_date)
and (b.end_date between a.start_date and b.end_date ))
order by end_date desc
我正在尝试在 SQL Server 中做
【问题讨论】:
【参考方案1】:一种合理有效的方法是
WITH T1
AS (SELECT *,
MAX(end_date) OVER (PARTITION BY sID ORDER BY start_date) AS max_end_date_so_far
FROM YourTable),
T2
AS (SELECT *,
range_start = IIF(start_date <= LAG(max_end_date_so_far) OVER (PARTITION BY sID ORDER BY start_date), 0, 1),
next_range_start = IIF(LEAD(start_date) OVER (PARTITION BY sID ORDER BY start_date) <= max_end_date_so_far, 0, 1)
FROM T1)
SELECT SId,
start_date,
end_date
FROM T2
WHERE 0 IN ( range_start, next_range_start );
如果您在(sID, start_date) INCLUDE (end_date)
上有一个索引,则可以使用单次有序扫描来完成这项工作。
【讨论】:
哇,效果很好!谢谢!但是,有什么方法可以在不使用按功能分区/更简单的查询的情况下做到这一点? @koala - 这是针对性能而非语法简单性而优化的【参考方案2】:您的逻辑并不完全正确,尽管它几乎适用于您的示例数据。它失败的具体原因是因为between
包括端点,所以任何给定的行都匹配自身。也就是说,逻辑仍然不正确,因为它没有捕捉到这种情况:
a-------------a
b----b
这是正确的逻辑:
select a.*
from table a
where exists (select 1
from table b
where a.sid = b.sid and
a.start_date < b.end_date and
a.end_date > b.start_date and
(a.start_date <> b.start_date or -- filter out the record itself
a.end_date <> b.end_date
)
)
order by a.end_date;
重叠时间段(或任何类型的范围)的规则是,当时间段 1 在时间段 2 结束之前开始,而时间段 1 在时间段 2 开始之后结束时,时间段 1 与时间段 2 重叠。幸运的是,between
不需要或用于此目的。 (我强烈反对将 between
与日期/时间操作数一起使用。)
我应该注意到,当一个时间段在同一天结束另一个开始时,这个版本不考虑两个时间段重叠。这可以通过将<
和>
更改为<=
和>=
来轻松调整。
Here 是一个 SQL Fiddle。
【讨论】:
我的表还有很多其他的 sID。我尝试运行您的查询并在 sID=1 的位置对其进行过滤,但它仍然给我相同的结果。 @koala。 . .对。您没有标识每一行的唯一 ID,因此通常会有and a.id <> b.id
。我根据开始和结束日期添加了类似的逻辑。
现在,当我不对 sID=1 进行过滤时,它只会给我这 2 行,而不是任何其他 sID 的任何重叠日期范围
@koala。 . .答案中没有任何内容过滤到sID = 1
。您的查询一定有其他问题。我包含了一个 SQL Fiddle 来证明它可以工作。
你是对的,现在可以工作了!对此感到抱歉,谢谢!你能解释一下“a.start_date b.start_date or a.end_date b.end_date”背后的逻辑吗以上是关于如何在 SQL 中选择重叠的日期范围的主要内容,如果未能解决你的问题,请参考以下文章