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

时间:2018-12-11 08:25:29

标签: mysql sql datetime range overlap

我得到了一个表格,其中包含一些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,因为最大数目从13:00到14:00的重叠范围是3。

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

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
    )

但是此返回4是因为它检测到除第一个以外的所有范围,但这是错误的。

我已经找到了

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

我使用的是MysQL 5.7,但如有必要,可以升级到8。

2 个答案:

答案 0 :(得分:2)

此答案适用于包含窗口函数的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

获得此结果(将其称为“重叠表”)后,您可以轻松地找到输入间隔的最大值,如下所示:

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

答案 1 :(得分:0)

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

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