Ответ 1
SELECT *
FROM table1,table2
WHERE table2.start <= table1.end
AND (table2.end IS NULL OR table2.end >= table1.start)
У меня есть две таблицы, как с полями времени начала, так и времени окончания. Мне нужно найти для каждой строки в первой таблице все строки во второй таблице, где интервалы времени пересекаются.
Например:
<-----row 1 interval------->
<---find this--> <--and this--> <--and this-->
Прошу прокомментировать ваш ответ в виде SQL WHERE
-clause, и рассмотрим случай, когда время окончания во второй таблице может быть NULL
.
Целевая платформа - это SQL Server 2005, но могут быть интересны и решения других платформ.
SELECT *
FROM table1,table2
WHERE table2.start <= table1.end
AND (table2.end IS NULL OR table2.end >= table1.start)
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)
)
РЕДАКТИРОВАТЬ: Хорошо, не идите на мое решение, оно исполняется как дерьмо. Решение "where" в 14 раз быстрее. К сожалению,...
Некоторые статистические данные: работа на db с ~ 65000 записей для таблиц 1 и 2 (без индексирования), имеющих интервалы между двумя днями между началом и для каждой строки, работающие в SQLSMSE в течение 2 минут (не имеют терпение ждать)
Использование соединения: 8356 строк за 2 минуты
Использование где: 115436 строк за 2 минуты
Звучит очень сложно, пока вы не начнете работать с реверса. Ниже я проиллюстрировал ТОЛЬКО ХОРОШИЕ СЛУЧАИ (без перекрытий)! определяемый этими двумя простыми условиями, мы не имеем диапазонов перекрытия, если condA OR condB имеет значение TRUE, поэтому мы собираемся изменить их: NOT condA AND NOT CondB, в нашем случае я просто изменил знаки ( > стал < =)
/*
|--------| 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