Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Achatar/mesclar intervalos de tempo sobrepostos


Eu só criei uma consulta CTE, pois o problema é que pode haver uma cadeia de tempos sobrepostos, por exemplo. o registro 1 se sobrepõe ao registro 2, o registro 2 ao registro 3 e assim por diante. Isso é difícil de resolver sem CTE ou algum outro tipo de loop, etc. Por favor, tente de qualquer maneira.

A primeira parte da consulta CTE obtém os serviços que iniciam um novo grupo e não têm o mesmo horário de início de algum outro serviço (preciso ter apenas um registro que inicie um grupo). A segunda parte recebe aqueles que iniciam um grupo, mas há mais de um com o mesmo horário de início - novamente, preciso de apenas um deles. A última parte se acumula recursivamente no grupo inicial, tomando todos os serviços sobrepostos.

Aqui está SQLFiddle com mais registros adicionados para demonstrar diferentes tipos de tempos sobrepostos e duplicados.

Não consegui usar ServiceID pois teria que ser ordenado da mesma forma 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