Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 слияние интервалов  [new]
Lepsik
Member

Откуда: glubinka
Сообщений: 4256
есть такой набор данных

DECLARE @T TABLE (StartDate DATETIME, EndDate DATETIME, code int)
INSERT INTO @T (StartDate, EndDate, code)
        SELECT '2010-01-01','2010-03-31', 0 UNION SELECT '2010-04-01','2010-05-31', 3 
  UNION SELECT '2010-06-15','2010-06-25', 1 UNION SELECT '2010-06-26','2010-07-10', 2 
  UNION SELECT '2010-08-01','2010-08-05', 0 UNION SELECT '2010-08-01','2010-08-09', 0 
  UNION SELECT '2010-08-02','2010-08-07', 1 UNION SELECT '2010-08-08','2010-08-08', 1 
  UNION SELECT '2010-08-09','2010-08-12', 2 UNION SELECT '2010-07-04','2010-08-16', 2 
  UNION SELECT '2010-11-01','2010-12-31', 0 UNION SELECT '2010-03-01','2010-06-13', 1 


хочется для каждого кода слить интервалы если они перекрываются.

Знаю как сделать без учета кода

    SELECT s1.StartDate AS stDt, MIN(t1.EndDate) AS enDt
	  FROM @T s1 
		INNER JOIN @T t1 ON s1.StartDate <= t1.EndDate
		  AND NOT EXISTS(SELECT * FROM @T t2 
						 WHERE t1.EndDate >= t2.StartDate AND t1.EndDate < t2.EndDate) 
 	  WHERE NOT EXISTS(SELECT * FROM @T s2 
						 WHERE s1.StartDate > s2.StartDate AND s1.StartDate <= s2.EndDate) 
      GROUP BY s1.StartDate


по идее в простом запросе достаtочно поставить code в GROUP BY , но здесь так нe прокатит, - что делать?
17 сен 14, 23:27    [16588111]     Ответить | Цитировать Сообщить модератору
 Re: слияние интервалов  [new]
Lepsik
Member

Откуда: glubinka
Сообщений: 4256
всем спасибо все нашел

    SELECT s1.StartDate AS stDt, MIN(t1.EndDate) AS enDt, s1.code
	  FROM @T s1 
		INNER JOIN @T t1 ON s1.StartDate <= t1.EndDate AND s1.code=t1.code
		  AND NOT EXISTS(SELECT * FROM @T t2
						 WHERE t1.EndDate >= t2.StartDate AND t1.EndDate < t2.EndDate AND t1.code=t2.code) 
 	  WHERE NOT EXISTS(SELECT * FROM @T s2 
						 WHERE s1.StartDate > s2.StartDate AND s1.StartDate <= s2.EndDate AND s1.code=s2.code) 
      GROUP BY s1.StartDate, s1.code
	  ORDER BY code, s1.StartDate
17 сен 14, 23:39    [16588135]     Ответить | Цитировать Сообщить модератору
 Re: слияние интервалов  [new]
Добрый Э - Эх
Guest
Lepsik,

как вариант, попробуй такое:
--
-- Тестовый набор данных:
with
  t (StartDate, EndDate, code) 
    as (
         SELECT '2010-01-01','2010-03-31', 0 
   UNION SELECT '2010-08-01','2010-08-05', 0
   UNION SELECT '2010-08-01','2010-08-09', 0 
   UNION SELECT '2010-11-01','2010-12-31', 0

   UNION SELECT '2010-03-01','2010-06-13', 1    
   UNION SELECT '2010-06-15','2010-06-25', 1
   UNION SELECT '2010-08-02','2010-08-07', 1
   UNION SELECT '2010-08-08','2010-08-08', 1 

   UNION SELECT '2010-06-26','2010-07-10', 2 
   UNION SELECT '2010-07-04','2010-08-16', 2 
   UNION SELECT '2010-08-09','2010-08-12', 2
   
   UNION SELECT '2010-04-01','2010-05-31', 3     
       )
--
-- Основной запрос:
select code, min(StartDate) as x_StartDate, max(EndDate) as x_EndDate
  from (
         select StartDate, EndDate, code,
                sum(sog) over(partition by code 
                                  order by StartDate, EndDate) as grp_id
           from (
                  select StartDate, EndDate, code,
                         case 
                           when StartDate <= max(EndDate) 
                                               over(partition by code 
                                                        order by StartDate, EndDate 
                                                 rows between unbounded preceding
                                                          and 1 preceding) 
                             then 0 
                           else 1 
                         end as sog
                    from t
                ) as v0
       ) as v1
 group by grp_id, code
 order by 1, 2
on-line проверка на sqlfiddle.com

З.Ы.
Единственное, что скуль-сервер нужен от 2012 и выше...
18 сен 14, 07:34    [16588437]     Ответить | Цитировать Сообщить модератору
 Re: слияние интервалов  [new]
Lepsik
Member

Откуда: glubinka
Сообщений: 4256
спасибо Добрый Э - Эх все летает, но мне 2005-й надо поддерживать тоже :)
22 сен 14, 23:46    [16607562]     Ответить | Цитировать Сообщить модератору
 Re: слияние интервалов  [new]
Lepsik
Member

Откуда: glubinka
Сообщений: 4256
все равно медленно, на наборе в 1300 интервалов - 5 секунд. CLR выдает мгновенно на 25,000 интервалов
23 сен 14, 01:01    [16607719]     Ответить | Цитировать Сообщить модератору
 Re: слияние интервалов  [new]
HandKot
Member

Откуда: Sergiev Posad
Сообщений: 3058
а если так?
+
DECLARE @T TABLE (StartDate DATETIME, EndDate DATETIME, code int)
INSERT INTO @T (StartDate, EndDate, code)
    SELECT '2010-01-01','2010-03-31', 0 UNION SELECT '2010-04-01','2010-05-31', 3 
	UNION SELECT '2010-06-15','2010-06-25', 1 UNION SELECT '2010-06-26','2010-07-10', 2 
	UNION SELECT '2010-08-01','2010-08-05', 0 UNION SELECT '2010-08-01','2010-08-09', 0 
	UNION SELECT '2010-08-02','2010-08-07', 1 UNION SELECT '2010-08-08','2010-08-08', 1 
	UNION SELECT '2010-08-09','2010-08-12', 2 UNION SELECT '2010-07-04','2010-08-16', 2 
	UNION SELECT '2010-11-01','2010-12-31', 0 UNION SELECT '2010-03-01','2010-06-13', 1 

--нужна таблица календарь и лучше её сделать постоянной
declare @Calendar table (dt datetime)
insert into @Calendar(dt) 
	select dateadd(d, row_number() over (order by number), '20090101') from master.dbo.spt_values

--собственно сама выборка	
;
with cteDateList(code, DateCol,Grouping)
as(
	Select 
		t.code, 
		Calendar.Dt,       
		Calendar.Dt + dense_rank() over (partition by t.code order by Calendar.Dt desc)  
	from 
		@t t, @Calendar Calendar
	where 
		Calendar.Dt between StartDate and EndDate
)
Select 
	code,
	Min(DateCol) StartDate,
	Max(DateCol) EndDate
from 
	cteDateList
group by code, Grouping
order by 1
23 сен 14, 08:20    [16607955]     Ответить | Цитировать Сообщить модератору
 Re: слияние интервалов  [new]
host.13
Member

Откуда:
Сообщений: 263
HandKot,

А может перегнать даты в значения типа geometry и с ними попробовать сделать требуемое? http://msdn.microsoft.com/ru-ru/library/bb933960.aspx
23 сен 14, 10:36    [16608517]     Ответить | Цитировать Сообщить модератору
 Re: слияние интервалов  [new]
iap
Member

Откуда: Москва
Сообщений: 47144
host.13
А может перегнать даты в значения типа geometry
Lepsik
но мне 2005-й надо поддерживать тоже :)
23 сен 14, 10:45    [16608587]     Ответить | Цитировать Сообщить модератору
 Re: слияние интервалов  [new]
HandKot
Member

Откуда: Sergiev Posad
Сообщений: 3058
host.13
HandKot,

А может перегнать даты в значения типа geometry и с ними попробовать сделать требуемое? http://msdn.microsoft.com/ru-ru/library/bb933960.aspx

я сам пока с геометри не работал. Если сделаете и выложите результат, будет интересно
23 сен 14, 11:40    [16608970]     Ответить | Цитировать Сообщить модератору
 Re: слияние интервалов  [new]
aleks2
Guest
DECLARE @T TABLE (StartDate DATETIME, EndDate DATETIME, code int, id int identity)
INSERT INTO @T (StartDate, EndDate, code)
        SELECT '2010-01-01','2010-03-31', 0 UNION SELECT '2010-04-01','2010-05-31', 3 
  UNION SELECT '2010-06-15','2010-06-25', 1 UNION SELECT '2010-06-26','2010-07-10', 2 
  UNION SELECT '2010-08-01','2010-08-05', 0 UNION SELECT '2010-08-01','2010-08-09', 0 
  UNION SELECT '2010-08-02','2010-08-07', 1 UNION SELECT '2010-08-08','2010-08-08', 1 
  UNION SELECT '2010-08-09','2010-08-12', 2 UNION SELECT '2010-07-04','2010-08-16', 2 
  UNION SELECT '2010-11-01','2010-12-31', 0 UNION SELECT '2010-03-01','2010-06-13', 1 
    
DECLARE @B TABLE ( D DATETIME, c int, n int identity primary key clustered );
DECLARE @E TABLE ( D DATETIME, c int, n int identity primary key clustered );

insert @B(D, c)
  select StartDate, code 
    from @T t 
    where not exists( select * from @T tt where tt.code = t.code and tt.StartDate <= t.StartDate and t.StartDate <= tt.EndDate 
                        and ( tt.StartDate < t.StartDate or tt.id < t.id )
                     )
    order by code, StartDate

insert @E(D, c)
  select EndDate, code 
    from @T t 
    where not exists( select * from @T tt where tt.code = t.code and tt.StartDate <= t.EndDate and t.EndDate <= tt.EndDate 
                        and ( t.EndDate < tt.EndDate or tt.id < t.id )
    )
    order by code, EndDate


select b.D as StartDate, e.D as EndDate, b.c as code from @B b inner join @E e on b.n = e.n
23 сен 14, 16:43    [16611438]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить