我有这个示例数据集
ID StartDate EndDate
------------------------------
1 2014-01-05 2014-01-10
2 2014-01-06 2014-01-11
3 2014-01-07 2014-01-12
4 2014-01-08 2014-01-13
5 2014-01-09 2014-01-14
6 2014-01-26 2014-01-31
7 2014-01-27 2014-02-01
8 2014-01-28 2014-02-02
9 2014-01-29 2014-02-03
10 2014-01-30 2014-02-04
我想选择与提供的时间段重叠的任何行,以及与之重叠的任何行等等。
因此,如果我想选择2014-01-06至2014-01-07期间的任何行数
以下是直接重叠(立即重叠)
1 2014-01-05 2014-01-10
2 2014-01-06 2014-01-11
但我还需要与1和2重叠的行(子重叠)
3 2014-01-07 2014-01-12
4 2014-01-08 2014-01-13
5 2014-01-09 2014-01-14
如果3到5有重叠,也要返回它们。但在这种情况下,没有。
这是我到目前为止的尝试,但它有两个问题,我发现我不知道如何修复。
;WITH cte
AS
(
SELECT t.ID,
t.StartTime,
t.EndTime
FROM
dbo.Tasks AS t
UNION ALL
SELECT t.ID,
t.StartTime,
t.EndTime
FROM
dbo.Tasks AS t INNER JOIN
cte AS c ON t.StartTime < c.EndTime
AND t.EndTime > c.StartTime
)
SELECT * FROM cte AS a WHERE a.StartTime < @NewEnd
AND a.EndTime > @NewStart
当获得子重叠的重叠时段时,重新包含立即重叠并导致无限递归。其次,
SELECT * FROM cte AS a WHERE a.StartTime < @NewEnd
AND a.EndTime > @NewStart
where子句将过滤掉任何递归发现的重叠。
答案 0 :(得分:1)
我首先要弄清楚数据集中岛屿的位置,然后才能确定哪些岛屿与您的查询范围重叠:
declare @t table (ID int,StartDate date,EndDate date)
insert into @t(ID,StartDate,EndDate) values
(1 ,'20140105','20140110'),
(2 ,'20140106','20140111'),
(3 ,'20140107','20140112'),
(4 ,'20140108','20140113'),
(5 ,'20140109','20140114'),
(6 ,'20140126','20140131'),
(7 ,'20140127','20140201'),
(8 ,'20140128','20140202'),
(9 ,'20140129','20140203'),
(10 ,'20140130','20140204')
declare @Start date
declare @End date
select @Start='20140106',@End='20140107'
;With PotIslands as (
--Find ranges which aren't overlapped at their start
select StartDate,EndDate from @t t where
not exists (select * from @t t2 where
t2.StartDate < t.StartDate and
t2.EndDate >= t.StartDate)
union all
--Extend the ranges by any other ranges which overlap on the end
select pi.StartDate,t.EndDate
from PotIslands pi
inner join
@t t
on
pi.EndDate >= t.StartDate and pi.EndDate < t.EndDate
), Islands as (
select StartDate,MAX(EndDate) as EndDate from PotIslands group by StartDate
)
select * from Islands i where @Start <= i.EndDate and @End >= i.StartDate
结果:
StartDate EndDate
---------- ----------
2014-01-05 2014-01-14
如果您需要单独的行,现在可以将选定的岛加入@t
表,以进行简单的范围查询。
这是有效的,例如,如果某个岛内的任何行都包含在一个范围内,岛上的所有剩余行也将始终。所以我们先找到这些岛屿。
答案 1 :(得分:0)
这应该这样做,如果需要你可以将它放入一个函数中并使用交叉应用来连接到另一个表。我没有测试它,但它应该与最小(如果有)错误一起工作。
declare @rt table
(
ID int not null,
StartTime date not null,
EndTime date not null
)
insert into @rt (ID, StartTime, EndTime)
select t.*
from Tasks t
where (@StartTime <= t.StartTime and @EndTime > t.StartTime)
or (@StartTime < t.EndTime and @EndTime >= t.EndTime)
declare @found int = @@rowcount
while @found > 0
begin
insert into @rt (ID, StartTime, EndTime)
select t.*
from Tasks t
left join @rt rt
on (rt.StartTime <= t.StartTime and rt.EndTime > t.StartTime)
or (rt.StartTime < t.EndTime and rt.EndTime >= t.EndTime)
where t.ID not in (select ID from @rt)
set @found = @@rowcount
end
select * from @rt