2016-02-20 2 views
0

Как вычислить пересечение дат для произвольного количества временных рядов в SQL без циклов?пересечение дат для произвольного числа временных рядов в SQL

Учитывая, что у меня есть таблица с 3 столбцами

  1. GroupID
  2. Дата начала
  3. Дата окончания

для каждого GroupID есть несколько строк - так несколько начала/даты окончания per GroupId (внутри группы нет перекрытия)

Что бы я хотел сделать, это найти все пересекающиеся даты между всеми группами Таким образом, если группа 1 имеет следующие даты

1/1/2001 - 1/31/2001 
3/31/2001 - 4/5/2001 

Группа 2 имеет следующие

1/25/2001 - 5/1/2001 

Группа 3 имеет следующую

1/22/2001 - 4/1/2001 

выше всех пересекаются по адресу:

1/25/2001 - 1/31/2001 
3/31/2001 - 1/4/2001 

Как это сделать в SQL? Далее имеет логику для 2-х диапазонов дат в пределах одной таблицы, но мне это нужно для диапазонов дат п в одной таблице:

SELECT 
    case 
     when t1.StartDate > t2.StartDate then t1.StartDate 
     else t2.StartDate 
    END as StartDate, 
    CASE WHEN t1.EndDate < t2.EndDate THEN t1.EndDate 
     ELSE t2.EndDate 
    END as EndDate 
FROM Table1 t1 
JOIN Table1 t2 ON t1.StartDate <= t2.EndDate AND t1.EndDate >= t2.StartDate  

(примечание: В качестве дополнительного ограничения я делаю это в LINQ к SQL)

Заранее спасибо

+0

Совет. Полезно пометить вопросы базы данных как с помощью соответствующего программного обеспечения (MySQL, Oracle, DB2, ...) и версии, например. 'SQL-сервер-2014'. Различия в синтаксисе и особенностях часто влияют на ответы. – HABO

ответ

1

Вы можете сделать это, разделив даты в группах и используя совокупные суммы, а затем некоторые сравнения. В SQL Server 2012+, это выглядит следующим образом:

with g as (
     select groupid, start as dte, 1 as enters, 0 as exits 
     from t 
     union all 
     select groupid, dateadd(day, 1, end), 0, 1 
     from t 
    ), 
    gs as (
     select groupid, dte, sum(enters) as enters, sum(exits) as exits, 
      sum(sum(enters)) over (order by dte) as cumeenters, 
      sum(sum(exits)) over (order by dte) as cumexits 
     from g 
     group by dte, groupid 
    ) 
select ne, nextdte 
from (select gs.*, lead(dte) over (order by dte) as nextdte 
     from gs 
    ) gs 
where cumeenters - cumeexits = (select count(distinct groupid) from t); 

Обработка заключается в следующем:

  • Первый подзапрос отделяет даты начала и окончания в отдельные записи.
  • Второй накапливает начальные и конечные значения, чтобы получить кумулятивные значения.
  • Предложение where выбирает даты, где представлены все группы.

Here - это SQL-скрипт.

+0

Есть 3 отдельных группы. groupid 1 имеет 2 строки, groupid 2 и 2 имеют по 1 строке, умножить на 2 (для 1 строки как start, 1 row as end) = 4 строки, 2 строки и 2 строки соответственно (в cte 'g' '). как группы с двумя рядами достигают совокупности 3? http://sqlfiddle.com/#!6/33f6a/5 –

+0

удалите 'partition by' для cumenters & cumexists: http://sqlfiddle.com/#!6/515cd/1 –

+0

Вау - большое вам спасибо - это займет у меня пару дней, чтобы преобразовать это в linq – Stuart

Смежные вопросы