2008-09-22 17 views
21

Tengo dos tablas, ambas con campos de hora de inicio y hora de finalización. Necesito encontrar, para cada fila en la primera tabla, todas las filas en la segunda tabla donde los intervalos de tiempo se cruzan.¿Cuál es una forma simple y eficiente de encontrar filas con superposiciones de intervalos de tiempo en SQL?

Por ejemplo:

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

frase por favor su respuesta en forma de un WHERE -clause SQL, y considerar el caso en que la hora de finalización de la segunda tabla puede ser NULL.

La plataforma de destino es SQL Server 2005, pero las soluciones de otras plataformas también pueden ser de interés.

+2

posible duplicado de [Determinar si se superponen dos rangos de fechas] (http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap) –

+0

Presumiblemente, si el tiempo de finalización en la segunda tabla es NULL, debe tratarse como "el período no tiene un tiempo de finalización y continúa en el futuro". Eso es lo que hace la respuesta aceptada; es una interpretación común, pero no es la única interpretación posible. –

Respuesta

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

Tenga en cuenta que si el inicio y el fin denotan instancias en el tiempo, es posible que desee eliminar la igualdad de las comparaciones; de lo contrario, se considerarán intersecciones dos rangos incluso si uno termina en la misma instancia en el tiempo que el otro. –

+7

Demostrar: si dos intervalos no se superponen, entonces (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, no van para mi solución, que perfoms como una mierda. La solución "donde" es 14 veces más rápida. Vaya ...

Algunas estadísticas: ejecución en un db con ~ 65000 registros para la tabla 1 y 2 (sin indexación), con intervalos de 2 días entre el inicio y el final de cada fila, ejecutándose durante 2 minutos en SQLSMSE (no tienen la paciencia de esperar)

Usando unirse: 8356 filas en 2 minutos

Usando donde: 115436 filas en 2 minutos

1

su sonido muy complicado hasta que empezar a trabajar desde atrás. Abajo ilustré SOLAMENTE BUENOS CASOS (¡no se superponen)! definido por las 2 condiciones simples, no tenemos ningún solapamiento varía si CONDA O condB es TRUE, por lo que va a revertir los: NO CONDA Y NO CondB, en nuestro caso yo sólo invierte signos (> convirtió < =)

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

fecha de finalización puede ser nula: / –

Cuestiones relacionadas