2008-09-22 11 views
21

Mam dwie tabele, obie z polami czasu rozpoczęcia i czasu zakończenia. Muszę znaleźć, dla każdego wiersza w pierwszej tabeli, wszystkie wiersze w drugiej tabeli, w których przecinają się interwały czasowe.Co to jest prosty i skuteczny sposób na znalezienie wierszy z nakładającymi się odstępami czasu w SQL?

Na przykład:

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

Proszę fraza odpowiedź w postaci SQL WHERE -clause i rozważyć przypadek, gdy czas zakończenia w drugiej tabeli mogą być NULL.

Platformą docelową jest SQL Server 2005, ale mogą być również interesujące rozwiązania z innych platform.

+2

możliwy duplikat [Ustal, czy dwa zakresy dat pokrywają się] (http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap) –

+0

Przypuszczalnie, jeśli czas zakończenia w drugiej tabeli jest NULL, należy go traktować jako "okres nie ma końca i trwa w przyszłości". Tak właśnie działa zaakceptowana odpowiedź; jest to powszechna interpretacja, ale nie jest to jedyna możliwa interpretacja. –

Odpowiedz

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

Należy zauważyć, że jeśli początek i koniec oznaczają instancje w czasie, możesz chcieć usunąć równość z porównań, w przeciwnym razie dwa zakresy będą uważane za przecinające się, nawet jeśli jeden koniec w tej samej instancji w czasie, co drugi początek. –

+7

Wykazać: Jeśli dwa interwały nie zachodzą na siebie (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, nie idź do mojego rozwiązania, to perfoms jak gówno. Rozwiązanie "Gdzie" jest 14x szybsze. Ups ...

Niektóre statystyki: działa na bazie danych z ~ 65000 rekordów dla tabeli 1 i 2 (bez indeksowania), z przerwami między dwoma początkami i końcami dla każdego wiersza, trwającymi przez 2 minuty w SQLSMSE (nie mają cierpliwości czekać)

Korzystanie dołączyć: 8356 wierszy w 2 minuty

Korzystanie gdzie: 115436 wiersze w 2 minuty

1

To dźwięk bardzo skomplikowane, aż zaczniesz pracować z tyłu. Poniżej zilustrowałem TYLKO DOBRE SPRAWY (bez pokrywania się)! zdefiniowana przez tych 2 prostych warunkach, mamy nie pokrywają się waha, czy Conda LUB condB jest TRUE, więc idziemy do odwrócenia tych: NIE Conda I NIE CondB, w naszym przypadku po prostu odwrócone znaki (> stał < =)

/* 
|--------| 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

data zakończenia może być pusta: / –