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

Puis-je utiliser un CTE SQL Server pour fusionner des dates qui se croisent ?

Réécriture complète :

;WITH new_grp AS (
   SELECT r1.UserId, r1.StartTime
   FROM   @requests r1
   WHERE  NOT EXISTS (
          SELECT *
          FROM   @requests r2
          WHERE  r1.UserId = r2.UserId
          AND    r2.StartTime <  r1.StartTime
          AND    r2.EndTime   >= r1.StartTime)
   GROUP  BY r1.UserId, r1.StartTime -- there can be > 1
   ),r AS (
   SELECT r.RequestId, r.UserId, r.StartTime, r.EndTime
         ,count(*) AS grp -- guaranteed to be 1+
   FROM   @requests r
   JOIN   new_grp n ON n.UserId = r.UserId AND n.StartTime <= r.StartTime
   GROUP  BY r.RequestId, r.UserId, r.StartTime, r.EndTime
   )
SELECT min(RequestId) AS RequestId
      ,UserId
      ,min(StartTime) AS StartTime
      ,max(EndTime)   AS EndTime
FROM   r
GROUP  BY UserId, grp
ORDER  BY UserId, grp

Produit maintenant le résultat demandé et vraiment couvre tous les cas possibles, y compris les sous-groupes disjoints et les doublons. Consultez les commentaires sur les données de test dans le démo de travail sur data.SE .

  • CTE 1
    Trouvez les points (uniques !) dans le temps où commence un nouveau groupe d'intervalles qui se chevauchent.

  • CTE 2
    Compte les démarrages d'un nouveau groupe jusqu'à (et y compris) chaque intervalle individuel, formant ainsi un numéro de groupe unique par utilisateur.

  • SELECT final
    Fusionnez les groupes, prenez le début au plus tôt et la fin au plus tard pour les groupes.

J'ai rencontré quelques difficultés, car les fonctions de fenêtre T-SQL max() ou sum() ne pas accepter un ORDER BY clause dans a dans une fenêtre. Ils ne peuvent calculer qu'une seule valeur par partition, ce qui rend impossible le calcul d'une somme/compte courant par partition. Fonctionnerait dans PostgreSQL ou Oracle (mais pas dans MySQL, bien sûr - il n'a ni fonctions de fenêtre ni CTE).

La solution finale utilise un CTE supplémentaire et devrait être tout aussi rapide.