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

Aplatir les intervalles de temps qui se croisent

Voici une solution SQL uniquement. J'ai utilisé DATETIME pour les colonnes. Stocker l'heure séparément est une erreur à mon avis, car vous aurez des problèmes lorsque les heures dépasseront minuit. Vous pouvez ajuster cela pour gérer cette situation si vous en avez besoin. La solution suppose également que les heures de début et de fin ne sont PAS NULL. Encore une fois, vous pouvez ajuster au besoin si ce n'est pas le cas.

L'essentiel de la solution consiste à obtenir toutes les heures de début qui ne se chevauchent avec aucune autre période, à obtenir toutes les heures de fin qui ne se chevauchent avec aucune période, puis à faire correspondre les deux.

Les résultats correspondent à vos résultats attendus, sauf dans un cas, où la vérification manuelle donne l'impression que vous avez une erreur dans la sortie attendue. Le 6, il devrait y avoir une plage qui se termine au 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