这是一个类似的问题:TSQL get overlapping periods from datetime ranges但是有不同的结果请求。
这是表格:
create table period (
id int,
starttime datetime,
endtime datetime,
type varchar(64)
);
insert into period values (1,'2013-04-07 8:00','2013-04-07 13:00','Work');
insert into period values (2,'2013-04-07 14:00','2013-04-07 17:00','Work');
insert into period values (3,'2013-04-08 8:00','2013-04-08 13:00','Work');
insert into period values (4,'2013-04-08 14:00','2013-04-08 17:00','Work');
insert into period values (5,'2013-04-07 10:00','2013-04-07 11:00','Holyday'); /* 1h overlapping with 1*/
insert into period values (6,'2013-04-08 10:00','2013-04-08 20:00','Transfer'); /* 6h overlapping with 3 and 4*/
insert into period values (7,'2013-04-08 11:00','2013-04-08 12:00','Test'); /* 1h overlapping with 3 and 6*/
我需要唯一不重叠日期时间范围表。
在前面的示例中,结果将是:
'2013-04-07 08:00','2013-04-07 13:00'
'2013-04-07 14:00','2013-04-07 17:00'
'2013-04-08 08:00','2013-04-08 20:00'
如果可能是时间碎片,则不是很重要,例如:
'2013-04-08 08:00','2013-04-08 13:00'
'2013-04-08 12:00','2013-04-08 20:00'
- 编辑 -
另一个例子:
create table period (
id int,
starttime datetime,
endtime datetime,
type varchar(64)
);
insert into period values (1,'2013-06-13 8:30','2013-06-13 12:30','');
insert into period values (2,'2013-06-13 8:38','2013-06-13 12:38','');
insert into period values (3,'2013-06-13 13:18','2013-06-13 17:45','');
insert into period values (4,'2013-06-13 13:30','2013-06-13 17:30','');
insert into period values (5,'2013-06-13 20:00','2013-06-13 23:59','');
这应该返回:
2013-06-13 08:30 - 2013-06-13 12:38
2013-06-13 13:18 - 2013-06-13 17:45
2013-06-13 20:00 - 2013-06-13 23:59
答案 0 :(得分:2)
但是你只有一个非重叠的时期,或者我是否理解错误的问题?
select *
from period t
where id in (
select t1.id
from period t1
join period t2 on t1.id <> t2.id
where t2.endtime <= t1.starttime or t2.starttime >= t1.endtime
group by t1.id
having count(*) + 1 = (select count(*) from period)
)
结果:
'2013-04-07 14:00','2013-04-07 17:00'
更新:好的,您希望合并重叠范围。试试这个:
select starttime, endtime
from period
where id in (
select t1.id
from period t1
join period t2 on t1.id <> t2.id
where t2.endtime < t1.starttime or t2.starttime > t1.endtime
group by t1.id
having count(*) + 1 = (select count(*) from period)
)
union all
select min(start), max(fin) from (
select
case when t2.starttime < t1.starttime then t2.starttime else t1.starttime end as start,
case when t2.endtime < t1.endtime then t1.endtime else t2.endtime end as fin
from period t1
join period t2 on t1.id < t2.id
where t2.endtime >= t1.starttime and t2.starttime <= t1.endtime) overlaps
group by datepart(dd, start), datepart(dd, fin)
答案 1 :(得分:0)
我找到了这个解决方案......我认为这不是最好的方法,但似乎有效。
DECLARE @union_unique TABLE (id INT IDENTITY(1, 1) primary key ,starttime datetime,endtime datetime)
DECLARE @idset TABLE (id int)
DECLARE @i int
SET @i = 1
IF (SELECT COUNT(*) FROM period) > 0
WHILE (@i <= (SELECT MAX(id) FROM period))
BEGIN
delete from @idset
insert into @idset
select distinct t2.id
from period t1
join @union_unique t2 on convert(date, t1.starttime)=convert(date, t2.starttime)
where t1.id=@i and
(
t1.starttime >= t2.starttime and t1.starttime <= t2.endtime
or
t1.endtime >= t2.starttime and t1.endtime <= t2.endtime
or
t1.starttime <= t2.starttime and t1.endtime >= t2.endtime
)
if(select count(*) from @idset)=0
insert into @union_unique (starttime, endtime) select starttime, endtime from period where id=@i
else
BEGIN
insert into @union_unique (starttime, endtime)
select
min(starttime),
max(endtime)
from (
select starttime, endtime from @union_unique where id in (select id from @idset)
union
select starttime, endtime from period where id=@i
) alll
delete from @union_unique where id in (select id from @idset)
END
SET @i = @i + 1
END
select * from @union_unique order by starttime