2014-01-30 3 views
4

У меня есть таблица «Сервис» с миллионами строк. Каждая строка соответствует службе, предоставляемой персоналом в заданную дату и временной интервал (каждая строка имеет уникальный идентификатор). Бывают случаи, когда сотрудники могут предоставлять услуги в перекрывающиеся временные рамки. Мне нужно написать запрос, который объединяет перекрывающиеся интервалы времени и возвращает данные в формате, показанном ниже.Временные интервалы перекрытия сложения/слияния

Я пробовал группировать поля StaffID и Date и получать Min of BeginTime и Max of EndTime, но это не учитывает неперекрывающиеся временные рамки. Как я могу это сделать? Опять же, таблица содержит несколько миллионов записей, поэтому рекурсивный подход CTE может иметь проблемы с производительностью. Заранее спасибо.

служба Таблица

ID StaffID Date  BeginTime EndTime 
1  101  2014-01-01 08:00  09:00 
2  101  2014-01-01 08:30  09:30 
3  101  2014-01-01 18:00  20:30 
4  101  2014-01-01 19:00  21:00 

Выход

StaffID Date  BeginTime EndTime 
101  2014-01-01 08:00  09:30 
101  2014-01-01 18:00  21:00 

Вот еще выборочные данные, установленные с помощью запроса, предложенного вкладчиком. http://sqlfiddle.com/#!6/bfbdc/3

Первые две строки в наборе результатов должны быть объединены в один ряд (06: 00-08: 45), но он генерирует два ряда (06: 00-08: 30 & 06: 00-08: 45)

+0

Это только на время в течение одного дня? Есть ли какие-то времена, которые пересекают полночь? – Szymon

+0

Да, только раз в течение одного дня. Время не будет проходить полночь. – Thracian

ответ

2

Я только придумал запрос CTE, поскольку проблема в том, что может существовать цепочка перекрывающихся времен, например запись 1 перекрывается с записью 2, записью 2 с записью 3 и т. д. Это трудно разрешить без CTE или некоторых других типов петель и т. Д. Пожалуйста, дайте ему идти в любом случае.

Первая часть запроса CTE получает услуги, которые запускают новую группу, и не имеют того же времени запуска, что и некоторые другие службы (мне нужно иметь только одну запись, которая запускает группу). Вторая часть получает те, которые начинают группу, но есть более одного с одинаковым временем начала - опять же, мне нужен только один из них. Последняя часть рекурсивно формируется в стартовой группе, используя все перекрывающиеся службы.

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

Я не мог использовать ServiceID, как это нужно было бы заказывать так же, как BeginTime.

;with flat as 
(
select StaffID, ServiceDate, BeginTime, EndTime, BeginTime as groupid 
from services S1 
where not exists (select * from services S2 
where S1.StaffID = S2.StaffID 
and S1.ServiceDate = S2.ServiceDate 
and S2.BeginTime <= S1.BeginTime and S2.EndTime <> S1.EndTime 
and S2.EndTime > S1.BeginTime) 

    union all 

    select StaffID, ServiceDate, BeginTime, EndTime, BeginTime as groupid 
    from services S1 
where exists (select * from services S2 
where S1.StaffID = S2.StaffID 
and S1.ServiceDate = S2.ServiceDate 
and S2.BeginTime = S1.BeginTime and S2.EndTime > S1.EndTime) 
    and not exists (select * from services S2 
where S1.StaffID = S2.StaffID 
and S1.ServiceDate = S2.ServiceDate 
and S2.BeginTime < S1.BeginTime 
and S2.EndTime > S1.BeginTime) 

union all 

select S.StaffID, S.ServiceDate, S.BeginTime, S.EndTime, flat.groupid 
from flat 
inner join services S 
on flat.StaffID = S.StaffID 
and flat.ServiceDate = S.ServiceDate 
and flat.EndTime > S.BeginTime 
and flat.BeginTime < S.BeginTime and flat.EndTime < S.EndTime 
) 

select StaffID, ServiceDate, MIN(BeginTime) as begintime, MAX(EndTime) as endtime 
from flat 
group by StaffID, ServiceDate, groupid 
order by StaffID, ServiceDate, begintime, endtime 
+0

Спасибо, Шимон, за это решение. Значение «BeginTime» не будет уникальным для каждого дня, но есть другое поле (ServiceID), которое уникально для каждой записи в таблице «service». Мы можем использовать это поле для улучшения запроса. Я проверю это решение и скоро отправлю отзыв. Опять же, спасибо за ваше время! – Thracian

+0

Szymon, вот ваш запрос с данными примера. Первые две строки в наборе результатов должны быть объединены в одну строку (06: 00-08: 45), но она генерирует две строки (06: 00-08: 30 и 06: 00-08: 45) http: // sqlfiddle.com/#!6/bfbdc/3 – Thracian

+0

@Thracian Спасибо за то, что вы подготовили свой вопрос так хорошо. Я обновил свой запрос, чтобы удовлетворить больше дел - надеюсь, теперь все это охвачено. Я думаю, что все виды дублирования и дублирования времени должны быть рассмотрены. Я включил скрипт SQL с большим количеством записей, чтобы продемонстрировать это. – Szymon

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