2010-05-27 6 views
4

J'ai une table avec les dates et heures de début et de fin que j'ai besoin de déterminer si un chevauchement et pas tout à fait sûr le meilleur chemin à parcourir. Initialement, je pensais utiliser un curseur imbriqué comme indiqué ci-dessous qui fonctionne, mais je vérifie deux fois les mêmes enregistrements les uns par rapport aux autres et je suis sûr que ce n'est pas très efficace. Par exemple: cette table entraînerait un chevauchement.Comment vérifier les dates ne se chevauchent pas dans une table en utilisant TSQL

id start      end 
------------------------------------------------------- 
1 2009-10-22 10:19:00.000  2009-10-22 11:40:00.000 
2 2009-10-22 10:31:00.000  2009-10-22 13:34:00.000 
3 2009-10-22 16:31:00.000  2009-10-22 17:34:00.000 

Declare @Start datetime, @End datetime, @OtherStart datetime, @OtherEnd datetime, @id int, @endCheck bit 

Set @endCheck = 0 

DECLARE Cur1 CURSOR FOR 
     select id, start, end from table1 

OPEN Cur1 
FETCH NEXT FROM Cur1 INTO @id, @Start, @End 
WHILE @@FETCH_STATUS = 0 AND @endCheck = 0 
BEGIN 
    -- Get a cursor on all the other records 
    DECLARE Cur2 CURSOR FOR 
      select start, end from table1 
       and id != @id AND start < @end 
    OPEN Cur2 
    FETCH NEXT FROM Cur2 INTO @OtherStart, @OtherEnd 
    WHILE @@FETCH_STATUS = 0 AND @endCheck = 0 
    BEGIN 

      if (@Start > @OtherStart AND @Start < @OtherEnd OR 
       @End > @OtherStart AND @End < @OtherEnd) 
       or 
       (@OtherStart > @Start AND @OtherStart < @End OR 
       @OtherEnd > @Start AND @OtherEnd < @End) 

      BEGIN 
       SET @endCheck = 1 
      END 

      FETCH NEXT FROM Cur2 INTO @OtherStart, @OtherEnd 
    END 
    CLOSE Cur2 
    DEALLOCATE Cur2 

    FETCH NEXT FROM Cur1 INTO @id, @Start, @End 
END 
CLOSE Cur1 
DEALLOCATE Cur1 
+0

est là une raison quelconque vous ne mettez pas une clause WHERE votre deuxième curseur pour sélectionner uniquement les enregistrements qui ont un début avant la date de fin de l'enregistrement en cours (par exemple, id!= @id ET start <@end)? – Zachary

+0

non, bon point. – Jon

Répondre

7
  • Tout d'abord, nous allons examiner de manière exhaustive ce que un moyen de « chevauchement » et optimisez votre expression booléenne.

Un chevauchement est l'une des conditions suivantes:

 
       Start1      End1 
--------------------------------------------------------------------------------- 
Start2      End2 
Start2              End2 
          Start2       End2 

et n'est pas l'une des conditions suivantes:

 
       Start1      End1 
--------------------------------------------------------------------------------- 
Start2 End2 
                 Start2 End2 

Si vous regardez attentivement, vous remarquerez Start2 < End1 AND End2 > Start1 définit cette relation, vous pouvez donc réduire votre expression à ceci.


  • Deuxièmement, vous pouvez mettre ceci dans une condition WHERE pour votre curseur au lieu de boucle à travers chaque ligne et la vérification. Troisièmement, puisque vous vérifiez simplement si quelque chose existe ou non, vous pouvez utiliser une clause IF EXISTS au lieu de faire une boucle sur un curseur et de vérifier. Enfin, vous pouvez condenser le tout en une seule requête en utilisant un INNER JOIN sur lui-même ou WHERE EXISTS, selon la manière dont vous voulez que votre sortie finale apparaisse. Pour obtenir tous les chevauchements dans la table, vous pouvez essayer quelque chose comme ce qui suit (le t2.id > t1.id est de ne se chevauchent chaque fois):

    SELECT t1.id, t2.id 
    FROM MyTable t1 
    INNER JOIN MyTable t2 ON t2.id > t1.id 
             AND t2.start < t1.end AND t2.end > t1.start 
    
+0

@ShaneCourtrille Merci pour l'édition, mais la condition que vous avez ajouté était déjà là (voir la deuxième ligne). –

+0

J'ai ajouté la deuxième ligne où la nouvelle plage de dates contient la plage de dates d'origine. Vous aviez deux lignes dans lesquelles il y avait au moins une partie de la nouvelle plage de dates à l'intérieur de la plage de dates d'origine. Dans la 2ème ligne d'origine, par exemple, Start 2 était dans Start1/End1. –

+0

@ShaneCourtrille Non, en fait vous avez ajouté une quatrième ligne qui était exactement la même que ma deuxième ligne. Ce que vous voyez maintenant est ramené à exactement ce qu'il était avant votre édition ... (vérifiez l'historique des révisions) Quoi qu'il en soit, nous sommes d'accord que cette version est correcte? –

3

Je ne suis pas certain de ce que vous souhaitez la sortie résultante à ressembler, mais vous pouvez essayer ceci:

SELECT 
    TD1.* 
FROM 
    table1 TD1 
    JOIN table1 TD2 ON 
     TD1.start BETWEEN TD2.start AND TD2.[end] 
     AND TD1.id != TD2.id 
1

Vous pouvez essayer cette requête. Essentiellement, il sélectionne l'ID de table1 si l'heure de début se produit entre l'heure de début et l'heure de fin de tout autre enregistrement.

Cela vous obtiendrait toutes les entrées qui "ont sauté le pistolet" et a commencé avant qu'une autre entrée se termine.

select id 
from table1 f1 
where exists(
    select 1 
    from table1 f2 
    where f1.id <> f2.id 
     AND f1.start >= f2.start 
     AND f1.start <= f2.[end] 
) 
1

Je pense que tout ce que vous devez faire est de comparer la date de fin à la date de début suivante pour déterminer les chevauchements. Cela pourrait renvoyer des doublons et vous pourriez vouloir lancer un DISTINCT si vous voulez seulement une copie de chaque chevauchement.

SELECT a.* FROM Table1 a 
INNER JOIN Table1 b 
ON a.End > b.Start AND a.id <> b.id 
Questions connexes