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

Aplanamiento de intervalos de tiempo que se cruzan

Aquí hay una solución solo de SQL. Usé DATETIME para las columnas. Almacenar la hora por separado es un error en mi opinión, ya que tendrás problemas cuando las horas pasen de la medianoche. Sin embargo, puede ajustar esto para manejar esa situación si es necesario. La solución también supone que las horas de inicio y finalización NO SON NULAS. Nuevamente, puede ajustar según sea necesario si ese no es el caso.

La esencia general de la solución es obtener todas las horas de inicio que no se superponen con ningún otro período, obtener todas las horas de finalización que no se superponen con ningún período y luego unirlas.

Los resultados coinciden con sus resultados esperados, excepto en un caso, en el que al verificar a mano parece que tiene un error en su salida esperada. El día 6 debe haber un intervalo que termine en 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