sql >> Base de Datos >  >> RDS >> Sqlserver

Aplanar/combinar intervalos de tiempo superpuestos

Solo se me ocurrió una consulta CTE porque el problema es que puede haber una cadena de tiempos superpuestos, p. el registro 1 se superpone con el registro 2, el registro 2 con el registro 3 y así sucesivamente. Esto es difícil de resolver sin CTE o algún otro tipo de bucles, etc. Pruébelo de todos modos.

La primera parte de la consulta CTE obtiene los servicios que inician un nuevo grupo y no tienen la misma hora de inicio que algún otro servicio (necesito tener solo un registro que inicie un grupo). La segunda parte obtiene aquellos que inician un grupo, pero hay más de uno con la misma hora de inicio; nuevamente, solo necesito uno de ellos. La última parte se acumula recursivamente en el grupo inicial, tomando todos los servicios superpuestos.

Aquí está SQLFiddle con más registros agregados para demostrar diferentes tipos de tiempos superpuestos y duplicados.

No pude usar ServiceID ya que tendría que ordenarse de la misma manera que 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