Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Appiattisci/unisci gli intervalli di tempo sovrapposti

Mi è venuta in mente una query CTE solo perché il problema è che potrebbe esserci una catena di tempi sovrapposti, ad es. il record 1 si sovrappone al record 2, il record 2 al record 3 e così via. Questo è difficile da risolvere senza CTE o altri tipi di loop, ecc. Prova comunque.

La prima parte della query CTE ottiene i servizi che avviano un nuovo gruppo e non hanno la stessa ora di inizio di altri servizi (ho bisogno di un solo record che avvia un gruppo). La seconda parte raccoglie quelli che iniziano un gruppo ma ce n'è più di uno con lo stesso orario di inizio - di nuovo, ne ho bisogno solo uno. L'ultima parte si accumula ricorsivamente sul gruppo di partenza, prendendo tutti i servizi sovrapposti.

Ecco SQLFiddle con più record aggiunti per dimostrare diversi tipi di volte sovrapposte e duplicate.

Non ho potuto utilizzare ServiceID in quanto dovrebbe essere ordinato allo stesso modo di 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