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

Achatamento de intervalos de tempo de interseção


Aqui está uma solução somente SQL. Eu usei DATETIME para as colunas. Armazenar a hora separada é um erro na minha opinião, pois você terá problemas quando as horas passarem da meia-noite. Você pode ajustar isso para lidar com essa situação, se necessário. A solução também assume que os horários de início e término NÃO são NULL. Novamente, você pode ajustar conforme necessário, se esse não for o caso.

A essência geral da solução é obter todos os horários de início que não se sobrepõem a nenhum outro período, obter todos os horários de término que não se sobrepõem a nenhum período e, em seguida, combinar os dois.

Os resultados correspondem aos resultados esperados, exceto em um caso, em que a verificação manual parece que você cometeu um erro na saída esperada. No dia 6 deve haver um período que termina em 2009-06-06 10:18:45.000.
SELECT
     ST.start_time,
     ET.end_time
FROM
(
     SELECT
          T1.start_time
     FROM
          dbo.Test_Time_Spans T1
     LEFT OUTER JOIN dbo.Test_Time_Spans T2 ON
          T2.start_time < T1.start_time AND
          T2.end_time >= T1.start_time
     WHERE
          T2.start_time IS NULL
) AS ST
INNER JOIN
(
     SELECT
          T3.end_time
     FROM
          dbo.Test_Time_Spans T3
     LEFT OUTER JOIN dbo.Test_Time_Spans T4 ON
          T4.end_time > T3.end_time AND
          T4.start_time <= T3.end_time
     WHERE
          T4.start_time IS NULL
) AS ET ON
     ET.end_time > ST.start_time
LEFT OUTER JOIN
(
     SELECT
          T5.end_time
     FROM
          dbo.Test_Time_Spans T5
     LEFT OUTER JOIN dbo.Test_Time_Spans T6 ON
          T6.end_time > T5.end_time AND
          T6.start_time <= T5.end_time
     WHERE
          T6.start_time IS NULL
) AS ET2 ON
     ET2.end_time > ST.start_time AND
     ET2.end_time < ET.end_time
WHERE
     ET2.end_time IS NULL