2013-04-16 2 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' 

--EDIT--

Другой пример:

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

ответ

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' 

Update: Хорошо, так что вы хотите, чтобы объединить перекрывающихся диапазонов. Попробуйте следующее:

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 
Смежные вопросы