I want to find id of the bookings that are overlapped each other. Each booking belongs to 1 car and it always has start and end.
Here is the table:
CREATE TABLE booking (
id int(11) NOT NULL AUTO_INCREMENT,
car_id int(11),
start datetime,
end datetime,
primary key(id)
);
CREATE INDEX car_start_end on booking (car_id, start, end);
I want to return all the bookings that are overlapped with another booking. Display in pair in each row. E.g: if booking1 overlapped with booking2 and booking3, it must be shown as 2 pairs
+------------+----------+
| id1 | id2 |
+------------+----------+
| booking1 | booking2 |
| booking1 | booking3 |
+------------+----------+
Note that both booking must be on the same car.
No duplicate pairs. E.g if booking1 and booking2 has already been retrieved, there should not be another pair with booking2 and booking1.
Example a duplicated booking (showing the full booking details):
+------+---------------------+---------------------+--------+-----+---------------------+---------------------+
| id1 | start1 | end1 | car_id | id2 | start2 | end2 |
+------+---------------------+---------------------+--------+---------------------------+---------------------+
| 1 | 2019-01-01 12:00:00 | 2019-01-01 15:00:00 | 1 | 2 | 2019-01-01 14:00:00 | 2019-01-01 16:00:00 |
+------+---------------------+---------------------+--------+-----+---------------------+---------------------+
My current sql query:
SELECT b1.id, b2.id from booking b1
INNER JOIN booking b2 ON b1.car_id = b2.car_id
-- condition for overlapping detection
AND b1.start < b2.end
AND b1.end > b2.start
-- remove self overlap
AND b1.id < b2.id;
I also have index for:
(car_id, start, end)
id
.However I am not really satisfy with the result where I try with 1million records and it takes forever to run.
Anw to improve ? I am using mysql 5.6 on my local.
Edit: Update fiddle with 1000 random bookings data.
The following recommendations will help you in your SQL tuning process.
You'll find 3 sections below:
ALTER TABLE `booking` ADD INDEX `booking_idx_car_id_end` (`car_id`,`end`);
SELECT
b1.id,
b2.id
FROM
booking b1
INNER JOIN
booking b2
ON b1.car_id = b2.car_id
AND b1.start < b2.end
AND b1.end > b2.start
AND b1.id < b2.id