如何在 SQL 中选择重叠的日期范围

koa*_*ala 2 sql sql-server join

我有一个包含以下列的表: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
Run Code Online (Sandbox Code Playgroud)

我只想要结果中的第 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
Run Code Online (Sandbox Code Playgroud)

我正在尝试在 SQL Server 中做

Gor*_*off 6

您的逻辑并不完全正确,尽管它几乎适用于您的示例数据。它失败的具体原因是因为between包含端点,所以任何给定的行都与自身匹配。也就是说,逻辑仍然不正确,因为它没有捕获这种情况:

 a-------------a
      b----b
Run Code Online (Sandbox Code Playgroud)

这是正确的逻辑:

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;
Run Code Online (Sandbox Code Playgroud)

重叠时间段(或任何类型的范围)的规则是,当时间段 1 在时间段 2 结束之前开始并且时间段 1 在时间段 2 开始之后结束时,时间段 1 与时间段 2 重叠。令人高兴的是,没有必要或没有用于between此目的。between(我强烈反对与日期/时间操作数一起使用。)

我应该指出,当一个时间段在另一个时间段开始的同一天结束时,该版本不考虑两个时间段重叠。<通过将和更改><=和可以轻松调整>=

是一个 SQL Fiddle。


Mar*_*ith 6

合理有效地做到这一点的一种方法是

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 ); 
Run Code Online (Sandbox Code Playgroud)

如果您(sID, start_date) INCLUDE (end_date)对此有索引,则可以通过单次有序扫描执行工作。