Я думал о том, как я могу упростить проблему, представленную здесь. Сложный MySQL Query — Проверка перекрывающихся интервалов DATE
По сути, за вычетом всей причудливой магии с датами это просто проблема проверки перекрывающихся интервалов. Ведь даты можно считать числами, и это может облегчить логику. Представьте себе следующую таблицу:
Schedules
schedule_id | start | end
1 | 1 | 3
2 | 4 | 7
3 | 8 | 13
4 | 15 | 16
5 | 18 | 24
6 | 25 | 28
Я пытаюсь вставить новый интервал так, чтобы [a, b] не перекрывался ни с каким другим интервалом. Соображения:
Смотрите следующее изображение. Это представляет границы того, что можно, а что нельзя вставлять. http://i.stack.imgur.com/jE59w.png
Использование следующих сокращений:
условие перекрытия двух диапазонов (старого и нового): (OS < NE) AND (OE > NS)
Хотя решение может быть не тривиальным, его не так сложно найти:
Нет наложения, если новый диапазон полностью до или после существующего диапазона: [new] <= [old] OR [old] <= [new]
и это означает, что:
(NE <= OS) OR (OE <= NS)
Обсуждая это утверждение, мы получаем условие перекрытия:
!( (NE <= OS) OR (OE <= NS) )
Сейчас использую Закон де Моргана мы можем написать это как
!(NE <= OS) AND !(OE <= NS)
И это эквивалентно
(NE > OS) AND (OE > NS)
который можно переписать как
(OS < NE) AND (OE > NS)
Теперь мы можем найти все перекрывающиеся диапазоны, используя
SELECT o.*
FROM Schedules o
WHERE o.start < :new_end
AND o.end > :new_start
Вы можете сформулировать вставку как:
insert into schedules(start, end)
select s, e
from (select $start s, $end as e) t
where not exists (select 1
from schedules s2
where s.start <= t.end and s.end >= t.start
);
Это будет только вставить значение, если оно не перекрывается с существующей строкой в таблице.