我有一个包含以下列的表: sID,start_date和end_date
有些值如下:
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中执行
答案 0 :(得分:3)
合理有效地实现这一目标的一种方法是
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)
上有索引,则可以使用单个有序扫描执行工作。
答案 1 :(得分:0)
您的逻辑并不完全正确,尽管它几乎适用于您的样本数据。失败的具体原因是因为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小提琴。