2008-09-22 5 views
21

J'ai deux tables, à la fois avec des champs de début et de fin. J'ai besoin de trouver, pour chaque ligne du premier tableau, toutes les lignes de la deuxième table où les intervalles de temps se croisent.Qu'est-ce qu'un moyen simple et efficace de trouver des lignes avec des chevauchements d'intervalles de temps dans SQL?

Par exemple:

  <-----row 1 interval-------> 
<---find this--> <--and this--> <--and this--> 

phrase S'il vous plaît votre réponse sous la forme d'un SQL WHERE -clause, et considérer le cas où peut être NULL la fin des temps dans la deuxième table.

La plate-forme cible est SQL Server 2005, mais les solutions d'autres plates-formes peuvent également vous intéresser.

+2

duplication possible de [Déterminer si deux plages de dates se chevauchent] (http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap) –

+0

On peut supposer que si l'heure de fin dans la deuxième table est NULL, il devrait être traité comme «la période n'a pas de fin et continue dans le futur». C'est ce que la réponse acceptée fait; c'est une interprétation commune, mais ce n'est pas la seule interprétation possible. –

Répondre

49
SELECT * 
FROM table1,table2 
WHERE table2.start <= table1.end 
AND (table2.end IS NULL OR table2.end >= table1.start) 
+0

Notez que si le début et la fin indiquent des instances dans le temps, vous pouvez supprimer l'égalité des comparaisons, sinon deux plages seront considérées comme se croisant même si une extrémité se trouve dans la même instance au moment où l'autre démarre. –

+7

Prouver: Si deux intervalles ne se chevauchent pas (s2> e1 || e2 e1 || e2 = s1). – Stanislav

2
select * from table_1 
right join 
table_2 on 
(
table_1.start between table_2.start and table_2.[end] 
or 
table_1.[end] between table_2.start and table_2.[end] 
or 
(table_1.[end] > table_2.start and table_2.[end] is null) 
) 

EDIT: Ok, ne vont pas pour ma solution, comme de la merde, il effectue ensuite. La solution "où" est 14 fois plus rapide. Oops ...

Quelques statistiques: s'exécutant sur une base de données avec ~ 65000 enregistrements pour les tables 1 et 2 (aucune indexation), avec des intervalles de 2 jours entre le début et la fin pour chaque ligne, s'exécutant pendant 2 minutes dans SQLSMSE (ne pas la patience d'attendre)

en utilisant rejoindre: 8356 lignes en 2 minutes

Utilisation où: 115436 lignes en 2 minutes

1

C'est son très compliqué jusqu'à ce que vous commencez à travailler de la marche arrière. Ci-dessous, j'ai illustré seulement de bons cas (pas de chevauchements)! défini par ces 2 conditions simples, nous avons pas de chevauchement varie si Conda OU condB est VRAI, donc nous allons inverser les: PAS Conda ET NON CondB, dans notre cas que je viens renversé des signes (> est devenu < =)

/* 
|--------| A        \___ CondA: b.ddStart > a.ddEnd 
      |=========| B    / \____ CondB: a.ddS > b.ddE 
          |+++++++++| A  /
*/ 
--DROP TABLE ran 
create table ran (mem_nbr int, ID int, ddS date, ddE date) 
insert ran values 
(100, 1, '2012-1-1','2012-12-30'), ----\ ovl 
(100, 11, '2012-12-12','2012-12-24'), ----/ 
(100, 2, '2012-12-31','2014-1-1'), 
(100, 3, '2014-5-1','2014-12-14') , 

(220, 1, '2015-5-5','2015-12-14') , ---\ovl 
(220, 22, '2014-4-1','2015-5-25') , ---/ 
(220, 3, '2016-6-1','2016-12-16') 

select DISTINCT a.mem_nbr , a.* , '-' [ ], b.dds, b.dde, b.id 
FROM ran a 
join ran b on a.mem_nbr = b.mem_nbr   -- match by mem# 
       AND  a.ID <> b.ID   -- itself 
        AND  b.ddS <= a.ddE  -- NOT b.ddS > a.ddE  
        AND  a.ddS <= b.ddE  -- NOT a.ddS > b.ddE 
+0

date de fin peut être null: / –

Questions connexes