2013-04-16 62 views
0

這是一個這樣的問題:TSQL get overlapping periods from datetime ranges但有不同的結果請求。TSQL得到唯一(不重疊)日期時間範圍

這是表:

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年6月13日08:30 - 2013年6月13日12:38

2013年6月13日13:18 - 2013年6月13日17:45

2013-06-13 20:00 - 2013-06-13 23:59

回答

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) 
+0

也許我的問題是不明確的,我不需要不從給定表重疊,但工會組給定表的不重疊的範圍(例如這些行:08:00-10:00 09:00-11:00變成08:00-11:00或者08:00-10:00和10:00-11:00)。 – Tobia

+0

我無法理解它,但它有效:-) – Tobia

+0

當我添加一個非重疊範​​圍但連續時,在這裏(插入導致錯誤)有一個小錯誤:http://sqlfiddle.com/#!6/ecc46/1 – Tobia

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 [email protected] 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 [email protected] 
      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 [email protected] 
       ) 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