检查新间隔是否重叠 - MySQL(或 PHP)
Checking if new interval overlaps - MySQL (or PHP)
我一直在思考如何简化这里提出的问题。 Complex MySQL Query - Checking for overlapping DATE intervals
从本质上讲,除去 DATES 的所有花哨魔法,这只是一个检查重叠间隔的问题。毕竟日期可以被认为是数字,它可以使逻辑更容易。想象以下 table:
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] 不与任何其他区间重叠。考虑因素:
- 是的,我可以将整个 table 拉入一个数组并对其进行 O(N) 搜索。好无聊
- 我更喜欢在 MySQL 中执行此操作,这样我就不必每次都拉下任意大的 table。
见下图。这表示可以插入和不能插入的范围。 http://i.stack.imgur.com/jE59w.png
您可以将插入词表述为:
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
);
这只会插入不与 table 中的现有行重叠的值。
使用以下缩写:
- [旧] := 现有范围
- [新] := 插入范围
- OS :=(旧)existing_range.start
- OE :=(旧)existing_range.end
- NS :=(新)inserting_range.start
- NE :=(新)inserting_range.end
两个范围(旧的和新的)重叠的条件是:(OS < NE) AND (OE > NS)
虽然解决方案可能并不简单,但实现起来并不难:
如果新范围完全在现有范围之前或之后,则没有重叠:[new] <= [old] OR [old] <= [new]
这意味着:
(NE <= OS) OR (OE <= NS)
协商这个语句我们得到重叠的条件:
!( (NE <= OS) OR (OE <= NS) )
现在使用De Morgan's law我们可以写成
!(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
我一直在思考如何简化这里提出的问题。 Complex MySQL Query - Checking for overlapping DATE intervals
从本质上讲,除去 DATES 的所有花哨魔法,这只是一个检查重叠间隔的问题。毕竟日期可以被认为是数字,它可以使逻辑更容易。想象以下 table:
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] 不与任何其他区间重叠。考虑因素:
- 是的,我可以将整个 table 拉入一个数组并对其进行 O(N) 搜索。好无聊
- 我更喜欢在 MySQL 中执行此操作,这样我就不必每次都拉下任意大的 table。
见下图。这表示可以插入和不能插入的范围。 http://i.stack.imgur.com/jE59w.png
您可以将插入词表述为:
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
);
这只会插入不与 table 中的现有行重叠的值。
使用以下缩写:
- [旧] := 现有范围
- [新] := 插入范围
- OS :=(旧)existing_range.start
- OE :=(旧)existing_range.end
- NS :=(新)inserting_range.start
- NE :=(新)inserting_range.end
两个范围(旧的和新的)重叠的条件是:(OS < NE) AND (OE > NS)
虽然解决方案可能并不简单,但实现起来并不难:
如果新范围完全在现有范围之前或之后,则没有重叠:[new] <= [old] OR [old] <= [new]
这意味着:
(NE <= OS) OR (OE <= NS)
协商这个语句我们得到重叠的条件:
!( (NE <= OS) OR (OE <= NS) )
现在使用De Morgan's law我们可以写成
!(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