【问题标题】:Count maximum number of overlapping date ranges in MySQL计算 MySQL 中重叠日期范围的最大数量
【发布时间】:2020-03-09 13:02:13
【问题描述】:

我对以下情况感到头疼。在 MySQL 中,我有一个包含 40000 多个条目的表,如下所示:

create table if not exists sessions
(
    startt datetime null,
    endt datetime null,
    id int auto_increment
        primary key
);

INSERT INTO sessions (startt, endt, id) VALUES 
('2020-02-06 10:33:55', '2020-02-06 10:34:41', 20356),
('2020-02-06 10:33:14', '2020-02-06 10:33:57', 20355),
('2020-02-06 10:32:55', '2020-02-06 10:33:32', 20354),
('2020-02-06 10:33:03', '2020-02-06 10:33:12', 20353),
('2020-02-06 10:31:38', '2020-02-06 10:32:41', 20352),
('2020-02-06 09:48:44', '2020-02-06 09:50:37', 20351);

SELECT * FROM sessions;
+---------------------+---------------------+-------+
| startt              | endt                | id    |
+---------------------+---------------------+-------+
| 2020-02-06 10:33:55 | 2020-02-06 10:34:41 | 20356 |
| 2020-02-06 10:33:14 | 2020-02-06 10:33:57 | 20355 |
| 2020-02-06 10:32:55 | 2020-02-06 10:33:32 | 20354 |
| 2020-02-06 10:33:03 | 2020-02-06 10:33:12 | 20353 |
| 2020-02-06 10:31:38 | 2020-02-06 10:32:41 | 20352 |
| 2020-02-06 09:48:44 | 2020-02-06 09:50:37 | 20351 |
+---------------------+---------------------+-------+
6 rows in set (0.00 sec)

小提琴https://www.db-fiddle.com/f/49bNZ7863gv6RThoPpuiid/0

日期和时间范围是会话。我想知道的是:一次存在的最大会话数是多少?

我发现了很多东西,比如如何找出一个日期是否在其他日期的范围内等。这并没有真正帮助,因为我想知道在最大峰值时有多少用户。

【问题讨论】:

标签: mysql datetime mariadb cumulative-sum


【解决方案1】:

这是一个使用窗口函数的选项(在 MySQL 8.0 中可用):

select dt, sum(nb) over(order by dt) sum_nb
from (
    select starttt dt, 1 nb from mytable 
    union all select endt, -1 from mytable 
) t
order by sum_nb desc
limit 1

这个想法是对数据集进行反透视;并发会话数在每个会话开始时增加 1,并在结束时减少 1。

然后,您可以使用窗口总和计算每个时间点的并发会话数。

最后一步是按会话数排序并仅保留第一行。

【讨论】:

  • 任意点的cummulative_sum 是重叠范围的数量。另一件需要注意的事情:按dt, nb 对UNION 进行排序,这样当项目重合时,“结束”在“开始”之前递减计数器。
  • 注意,我认为窗口函数是 O(N*N),所以即使是中等数量的项目也会很慢。
  • 我们可以在没有窗口函数的 MySQL 5.6 中做到这一点
【解决方案2】:

我将其表述为具有窗口函数的聚合:

select dt, sum(sum(inc)) over (order by dt) as overlapping
from (select starttt as dt, 1 as inc
      from mytable union all
      select endt, -1  as inc
      from mytable 
     ) t
group by dt
order by overlapping desc
limit 1;

【讨论】:

  • 我们可以用窗口函数来做吗? (我的意思是在 mysql 5.6 中)
猜你喜欢
  • 1970-01-01
  • 2020-02-20
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
相关资源
最近更新 更多