Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Aplatir/fusionner les intervalles de temps qui se chevauchent

Je n'ai proposé qu'une requête CTE car le problème est qu'il peut y avoir une chaîne de temps qui se chevauchent, par ex. l'enregistrement 1 chevauche l'enregistrement 2, l'enregistrement 2 avec l'enregistrement 3 et ainsi de suite. C'est difficile à résoudre sans CTE ou un autre type de boucles, etc. Essayez quand même.

La première partie de la requête CTE obtient les services qui démarrent un nouveau groupe et qui n'ont pas la même heure de démarrage qu'un autre service (j'ai besoin d'un seul enregistrement qui démarre un groupe). La deuxième partie reçoit ceux qui démarrent un groupe mais il y en a plus d'un avec la même heure de début - encore une fois, j'ai besoin d'un seul d'entre eux. La dernière partie s'appuie de manière récursive sur le groupe de départ, en prenant tous les services qui se chevauchent.

Voici SQLFiddle avec plus d'enregistrements ajoutés pour démontrer différents types d'heures qui se chevauchent et se dupliquent.

Je n'ai pas pu utiliser ServiceID car il devrait être commandé de la même manière 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