问题
I've been thinking on how I can simplify the problem presented here. Complex MySQL Query - Checking for overlapping DATE intervals
At it's heart, minus all the fancy magic with DATES this is simply a problem of checking for overlapping intervals. After all dates can be thought of as numbers and it may make the logic easier. Imagine the following table:
Schedules
schedule_id | start | end
1 | 1 | 3
2 | 4 | 7
3 | 8 | 13
4 | 15 | 16
5 | 18 | 24
6 | 25 | 28
I'm trying to insert a new interval such that [a,b] do not overlap with any other interval. The considerations:
- Yes, I can pull the whole table into an array and do an O(N) search on it. That's boring.
- I prefer to do this in MySQL so I don't have to pull down what can be an arbitrarily large table every time.
See the following image. This represents the bounds of what can and can not be inserted. http://i.stack.imgur.com/jE59w.png
回答1:
Using folowing abbreviations:
- [old] := existing range
- [new] := inserting range
- OS := (old) existing_range.start
- OE := (old) existing_range.end
- NS := (new) inserting_range.start
- NE := (new) inserting_range.end
the condition for overlaping of two ranges (old and new) is: (OS < NE) AND (OE > NS)
While the solution might be not trivial, its not that difficult to get there:
There is no overlaping if the new range is completly before or after the existing range: [new] <= [old] OR [old] <= [new]
and that means that:
(NE <= OS) OR (OE <= NS)
Negotiating this statement we get the condition for overlaping:
!( (NE <= OS) OR (OE <= NS) )
Now using De Morgan's law we can write it as
!(NE <= OS) AND !(OE <= NS)
And this is equivalent to
(NE > OS) AND (OE > NS)
wich can be rewriten as
(OS < NE) AND (OE > NS)
Now we can find all overlaping ranges using
SELECT o.*
FROM Schedules o
WHERE o.start < :new_end
AND o.end > :new_start
回答2:
You can phrase an insert as:
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
);
This will only insert the value if it doesn't overlap with an existing row in the table.
来源:https://stackoverflow.com/questions/34416146/checking-if-new-interval-overlaps-mysql-or-php