简体   繁体   English

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

[英]Count maximum number of overlapping date ranges in MySQL 5.6

I am creating a vehicle rental application.我正在创建一个汽车租赁应用程序。 I was trying find overlapping booking in given dates.我试图在给定的日期找到重叠的预订。 I come across a similar question Count maximum number of overlapping date ranges in MySQL but this only answered for MySQL 8.0.我遇到了一个类似的问题Count maximum number of duplicate date range in MySQL但这仅适用于 MySQL 8.0。

I modified above question for my problem.我针对我的问题修改了上述问题。 I need solution for MySQL 5.6 without window function.我需要没有 window function 的MySQL 5.6的解决方案。

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);

Suppose If I give start as 2020-02-05 and end as 2020-02-11, this should return 2, as maximum usage of vehicle 111, is 2 from 2020-02-06 to 2020-02-10假设如果我以 2020-02-05 开始并以 2020-02-11 结束,这应该返回 2,因为车辆 111 的最大使用量是 2 从 2020-02-06 到 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)

So overall output I am expecting for input start(2020-02-05) and end(2020-02-11)所以总体上 output 我期待输入 start(2020-02-05) 和 end(2020-02-11)

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

I need solution which covers followings我需要涵盖以下内容的解决方案

  • on passing start_date and end_date my query will return data only for that range在传递 start_date 和 end_date 我的查询将只返回该范围的数据
  • If no data found should return vehicle_id 0如果没有找到数据应该返回vehicle_id 0
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. PS。 Misprint in 4th row is corrected.更正了第 4 行的印刷错误。

The maximum number of overlaps occurs when a rental starts (although it might persist for a period of time, this is all you care about).租赁开始时会出现最大重叠次数(尽管它可能会持续一段时间,但这就是您所关心的)。

You can calculate this for each start using:您可以使用以下方法为每次开始计算:

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;

Then for the maximum:然后为最大值:

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 is a db<>fiddle. 是一个 db<>fiddle。

Performance on this type of query is never going to be as good as using window functions.此类查询的性能永远不会像使用 window 函数那样好。 However, an index on (vehicle_id, start, end) would help.但是, (vehicle_id, start, end)上的索引会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM