计算 MySQL 5.6 中重叠日期范围的最大数量

Count maximum number of overlapping date ranges in MySQL 5.6

我正在创建一个汽车租赁应用程序。我试图在给定日期找到重叠的预订。我遇到了一个类似的问题 但这只回答了 MySQL 8.0.

我针对我的问题修改了上面的问题。 我需要 MySQL 5.6 没有 window 功能的解决方案。

create table if not exists BOOKING
(
    start datetime null,
    end datetime null,
    vehicle_id varchar(255),
    id int auto_increment
        primary key
);

INSERT INTO BOOKING (start, end, vehicle_id)
VALUES
('2020-02-06 10:33:55', '2020-02-07 10:34:41', 111),
('2020-02-08 10:33:14', '2020-02-10 10:33:57', 111),
('2020-02-06 10:32:55', '2020-02-07 10:33:32', 222),
('2020-08-06 10:33:03', '2020-02-11 10:33:12', 111),
('2020-02-12 10:31:38', '2020-02-15 10:32:41', 111),
('2020-02-09 09:48:44', '2020-02-10 09:50:37', 222);

假设如果我给出开始时间为 2020-02-05 结束时间为 2020-02-11,这应该 return 2,因为车辆 111 的最大使用量从 2020-02-06 到 2 2020-02-10

5  6  7  8  9  10  11 
   <-->  <------>
   <---------------->     (Vehicle Id 111, ANSWER should be 2)

for vehicle id 222, (For same query)
5  6  7  8  9  10  11 
   <-->     <--->         (Vehicle Id 222, ANSWER should be 1)

所以我期望输入开始(2020-02-05)和结束(2020-02-11)的总体输出

+---------+-------+
| vehicle | usage |
+---------+-------+
| 111     | 2     |
| 222     | 1     |
+---------+-------+

我需要包含以下内容的解决方案

SELECT vehicle_id vehicle, MAX(cnt) `usage`
FROM ( SELECT booking.vehicle_id, timepoints.dt, COUNT(*) cnt
       FROM booking
       JOIN ( SELECT start dt FROM booking
              UNION ALL
              SELECT `end` FROM booking ) timepoints ON timepoints.dt BETWEEN booking.start AND booking.`end`
       GROUP BY booking.vehicle_id, timepoints.dt ) subquery
GROUP BY vehicle_id;

fiddle

PS。第 4 行的印刷错误已更正。

租赁开始时出现最大重叠次数(尽管它可能会持续一段时间,这就是您所关心的)。

您可以为每次启动计算此值:

SELECT b.vehicle_id, b.start, COUNT(*)
FROM booking b JOIN
     booking b2
     ON b2.vehicle_id = b.vehicle_id AND
        b2.start <= b.start AND
        b2.end > b.start
WHERE b.start <= $end and b.end >= $start
GROUP BY b.vehicle_id, b.start;

那么对于最大值:

SELECT vehicle_id, MAX(overlaps)
FROM (SELECT b.vehicle_id, b.start, COUNT(*) as overlaps
      FROM booking b JOIN
           booking b2
           ON b2.vehicle_id = b.vehicle_id AND
              b2.start <= b.start AND b2.end > b.start
      GROUP BY b.vehicle_id, b.start
     ) b
GROUP BY vehicle_id;

Here 是一个 db<>fiddle.

此类查询的性能永远不如使用 window 函数。但是,(vehicle_id, start, end) 上的索引会有所帮助。