确定重叠 DATETIME 范围的最大数量

Determine max number of overlapping DATETIME ranges

我有一个 table 有一些 DATETIME 范围,比如

id | start               | end
----------------------------------------------
1  | 2011-12-18 16:00:00 | 2011-12-18 17:00:00
2  | 2011-12-19 08:00:00 | 2011-12-19 10:00:00
3  | 2011-12-19 11:00:00 | 2011-12-19 13:00:00
4  | 2011-12-19 12:00:00 | 2011-12-19 14:00:00
5  | 2011-12-19 13:00:00 | 2011-12-19 15:00:00
6  | 2011-12-19 13:00:00 | 2011-12-19 14:00:00
7  | 2011-12-20 13:00:00 | 2011-12-20 14:00:00

因此,对于 2011-12-19 日,范围跨度如下:

8    9   10   11   12   13   14   15
<-------->
               <-------->
                    <-------->
                         <-------->
                         <---->

目标是,在插入新记录时,找到已经存在的重叠范围的最大数量:即:在插入新范围时 2011-12-19 12:00:00 - 2011-12-19 15:00:00 我想接收 3,因为最大重叠范围数为 3,从 13:00 到 14:00.

从现在开始,我设法拥有了这个

select
    count(*) as cnt
from
    mytable as p
where
    ( # check if new renge overlap existings ones
        (@start >= start and @start < end)
        or
        (@end > start and @end <= end)
    )
    or
    ( # check if existing range is included by new one
        start between @start and @end
        and
        end between @start and @end
    )

但是这个return4因为它检测除了第一个之外的所有范围,但是是错误的。

我已经找到了

但是所有这些问题都略有不同。

我在 MysQL 5.7,但如有必要,可以升级到 8。

考虑到开始和结束永远不会相同:

select
    count(*) as cnt
from
    mytable as p
where
    # check if new renge overlap existings ones
        (@start < end and @end > start);

此答案适用于包含 window 功能的 MySQL 8.0。解决方案的核心将是以下查询,它为数据中每个有趣的区间找到多个重叠区间:

select t2.startDt, t2.endDt, count(*) overlaps_count
from
(
    select lag(t1.dt) over (order by t1.dt) startDt, t1.dt endDt
    from
    (
        select startt dt from data
        union
        select endt dt from data
    ) t1
) t2
join data on t2.startDt < data.endt and t2.endDt > data.startt
group by t2.startDt, t2.endDt

DBFiddle DEMO

一旦你得到这个结果(我们称它为 Overlap table),那么你可以很容易地找到输入间隔的最大值,如下所示

with Overlap as
(
   -- the query above
)
select max(overlaps_count)
from Overlap 
where @start < endDt and @end > startDt