Объедините перекрывающиеся временные интервалы в SQL Server - PullRequest
2 голосов
/ 03 декабря 2011

У меня есть таблица с записями перекрывающихся временных интервалов.

Например: календарь (Id int, дата-время StartDate, дата-время EndDate, название события nvarchar (100), ...)

Записи будут выглядеть как

  1. 01/20/2011 08:15 AM --- 20.01.2011 08:40
  2. 01/20/2011 08:20 AM --- 20.01.2011 08:55
  3. 01/20/2011 12:30 --- 20.01.2011 13:15
  4. 01/20/2011 14:00 --- 20.01.2011 14:45
  5. 01/20/2011 14:15 --- 20.01.2011 14:30
  6. 01/21/2011 12:30 --- 21.01.2011 13:15
  7. .......
  8. .......

Таблица представляет расписание событий человека

Я хочу объединить перекрывающиеся слоты, чтобы получить:

  1. 01/20/2011 08:15 AM --- 20.01.2011 08:55
  2. 01/20/2011 12:30 --- 20.01.2011 13:15
  3. 01/20/2011 14:00 --- 20.01.2011 14:45
  4. 01/21/2011 12:30 --- 21.01.2011 13:15
  5. ...
  6. ...

Я застрял в этой части проблемы ... (Я удалил свой код, который вставил сюда, так как он выглядит искаженным. Я впервые использую stackoverflow.)

Часть моего фактического требования - найти временной интервал [t] (скажем, 25 минут) между двумя указанными датами, который я могу включить в расписание. [t] должен быть найден между 8:00 и 17:00 в любой день.

1 Ответ

2 голосов
/ 04 декабря 2011

Это интересный вопрос.

Для заданной даты , давайте рассмотрим перекрытия (я ввел все свои даты, как у вас, но для 01.01.2011):

SELECT        dt1.StartTime AS StartOverlap,
              CASE 
                WHEN dt1.EndTime > dt2.EndTime THEN dt1.EndTime
                ELSE dt2.EndTime
              END AS EndOverlap
FROM          datetimetest dt1, datetimetest dt2
WHERE         dt2.StartTime > dt1.StartTime
AND           dt2.StartTime < dt1.EndTime

Это дает мне:

StartOverlap        EndOverlap
01/01/2011 08:15:00 01/01/2011 08:55:00
01/01/2011 14:00:00 01/01/2011 14:45:00

Отлично, теперь мы знаем время начала и окончания, когда мы не можем использовать это перекрытие.

Как мы можем получить другие не перекрывающиеся времена?

Я бы посмотрел на все периоды времени, которые находятся в перекрывающихся диапазонах, а затем выбрал идентификаторы, которые не находятся в этом диапазоне дат:

SELECT id 
FROM (SELECT        dt1.StartTime AS StartOverlap,
                CASE 
                  WHEN dt1.EndTime > dt2.EndTime THEN dt1.EndTime
                  ELSE dt2.EndTime
                END AS EndOverlap
  FROM          datetimetest dt1, datetimetest dt2
  WHERE dt2.StartTime > dt1.StartTime
  AND dt2.StartTime < dt1.EndTime
 ) AS Overlaps, datetimetest dtt

WHERE dtt.StartTime >= Overlaps.StartOverlap 
AND dtt.EndTime <= Overlaps.EndOverlap

Это дает мне список всех идентификаторов, которые находятся в перекрытиях. Затем я просто выбираю все записи, которые НЕ находятся в перекрытиях:

SELECT StartTime, EndTime FROM datetimetest
WHERE id NOT IN(
SELECT id 
FROM (SELECT        dt1.StartTime AS StartOverlap,
                CASE 
                  WHEN dt1.EndTime > dt2.EndTime THEN dt1.EndTime
                  ELSE dt2.EndTime
                END AS EndOverlap
  FROM          datetimetest dt1, datetimetest dt2
  WHERE dt2.StartTime > dt1.StartTime
  AND dt2.StartTime < dt1.EndTime
 ) AS Overlaps, datetimetest dtt

WHERE dtt.StartTime >= Overlaps.StartOverlap 
AND dtt.EndTime <= Overlaps.EndOverlap)

Чтобы дать мне:

StartTime           EndTime
01/01/2011 12:30:00 01/01/2011 13:15:00

Затем я могу объединить оба запроса, чтобы получить список всех используемых временных интервалов.

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

...