2010-10-20 4 views
0

J'ai une table SQL Events (ID int, Event int, StartTime datetime, Duration int).sélectionnez événements chevauchement datetime avec SQL

Event est le code d'événement (1 = fonctionnement du système, 2 = pause)

Duration est le nombre de secondes que l'événement est actif.

J'aimerais obtenir la quantité de secondes événement 1 était actif, mais soustraire la durée de l'événement .

E.g. l'événement 1 était de 1h00 à 6h00, l'événement 2 de 0h00 à 2h00 et l'événement 2 de 5h00 à 6h00. La durée totale devrait être de 2h00 à 5h00 -> 3 heures.

Il est possible que je peux penser à: pour chaque événement trouver tous événements 2 qui peuvent recouper avec l'événement 1, et pour chaque événement dans cet ensemble: TRIM sa durée pour obtenir seulement partie qui était active pendant son événement 1.

par exemple pour mon événement 1 (1:00 - 6:00) je trouverai l'événement 2 (0:00 - 2:00), obtenir seulement la partie qui m'intéresse (1: 00-2: 00); trouver un autre événement 2 (5: 00-6: 00), obtenir la partie qui m'intéresse (c'est tout l'événement 5: 00-6: 00) - qui résume deux heures. La durée totale de l'événement 1 était de 5 heures; 5 heures - 2 heures (événement 2) est de 3 heures.

Mais cela ne fonctionnera pas s'il y a des milliers d'événements dans le laps de temps spécifié, donc je préfère un conseil de solution sans boucles (curseurs).

Répondre

1
;WITH CTE AS (
    SELECT 
     evnt2.id as ID, 
     sum(evnt1.duration) as Duration 
    from 
     #events evnt1 
     INNER JOIN #events evnt2 
      ON evnt1.id <> evnt2.id 
    WHERE 
     DATEADD(second, evnt1.duration, evnt1.starttime) 
     BETWEEN 
      evnt2.starttime AND DATEADD(second, evnt2.duration, evnt2.starttime) 
    GROUP BY evnt2.id 
) 
SELECT 
    #events.duration - CTE.duration, 
    * 
FROM 
    #events 
    INNER JOIN CTE 
     ON #events.id = CTE.id 
1

La façon la plus simple de penser à cela est de créer plusieurs auto-jointures. Je dis multiple parce que l'événement 2 peut commencer avant ou pendant l'événement 1.

est ici un peu de code qui répondra à votre question si l'événement 2 commence toujours avant l'événement 1.

select DateDiff(s,e1.StartTime, DateAdd(s,e2Before.Duration,e2Before.StartTime)) 
from events e1 
join events e2Before 
    on (e1.StartTime between e2Before.StartTime and DateAdd(s,e2Before.duration,e2Before.StartTime)) 
    and e1.event = 1 
    and e2Before.event = 2 

Pour répondre pleinement à la question , vous devrez ajouter une autre jointure avec certains des paramètres DateAdd échangés un peu pour répondre aux situations où l'événement 2 démarre après le démarrage de l'événement 1.