最大重叠日期时间,包含许多开始和结束时间

时间:2016-01-22 17:45:28

标签: mysql date concurrency date-range

经过一些实验和一些搜索,我发现这个查询给出了我需要的结果:

SET @start := '2015-12-12 00:00:00', @end := '2015-12-12 23:59:59';

SELECT Max(simultaneous_people), 
       Max(simultaneous_event), 
       boundary 
FROM   (SELECT Count(id)                AS simultaneous_people, 
               Count(DISTINCT uniqueId) AS simultaneous_event, 
               boundary 
        FROM   mytable 
               RIGHT JOIN (SELECT row_begin AS boundary 
                           FROM   mytable 
                           WHERE  row_begin BETWEEN @start AND @end 
                           UNION 
                           SELECT row_end 
                           FROM   mytable 
                           WHERE  row_end BETWEEN @start AND @end 
                           UNION 
                           SELECT @start 
                           UNION 
                           SELECT @end 
                           UNION 
                           SELECT Max(boundary) 
                           FROM   (SELECT Max(row_begin) AS boundary 
                                   FROM   mytable 
                                   WHERE  row_begin <= @start 
                                   UNION ALL 
                                   SELECT Max(row_end) 
                                   FROM   mytable 
                                   WHERE  row_end <= @end) t) t 
                       ON row_begin <= boundary 
                          AND boundary < row_end 
        WHERE  row_status = 1 
        GROUP  BY boundary) t;

同一时间内重叠时间段的最大数量。 但是我需要在许多时间间隔之间提取这些信息,例如10。 我无法找到如何使用以下查询在运行时构建的日历中提取此信息:

SELECT DATE_SUB(@date, INTERVAL @num MINUTE) AS endSample, 
       DATE_SUB(@date, INTERVAL @num:=@num+@lenght MINUTE) AS startSample
FROM 
  mytable,
  (SELECT @num:=0) num
LIMIT 10;

我正在使用MySQL,不幸的是我无法在此数据库中存储任何数据/表/过程/视图。

如果有人知道如何以有效的方式合并这两个查询将会很棒。 谢谢!

更新:

我的架构:

CREATE TABLE mytable (
  id         INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  uniqueId   INT,
  row_status INT,
  row_begin DATETIME,
  row_end   DATETIME
);

有些数据只用了一天,只测试小时粒度:

INSERT INTO mytable (uniqueId, row_status, row_begin, row_end)
VALUES
  (1, 1, '2015-12-12 08:00:00', '2015-12-12 12:00:00'),
  (1, 1, '2015-12-12 08:00:00', '2015-12-12 14:00:00'),
  (1, 1, '2015-12-12 08:00:00', '2015-12-12 14:00:00'),
  (2, 1, '2015-12-12 13:00:00', '2015-12-12 14:00:00'),
  (2, 1, '2015-12-12 13:00:00', '2015-12-12 16:00:00'),
  (3, 1, '2015-12-12 09:00:00', '2015-12-12 12:00:00'),
  (3, 0, '2015-12-12 08:00:00', '2015-12-12 16:00:00');

我刚刚添加了SQL Fiddle

在这里,我必须手动设置每个日期范围的变量,但我需要能够设置“日历”,并能够指定日历是日,时,小时还是分钟,调整@length变量。

我的解决方案的第一部分取自this answer

我想要的输出,以时间粒度为单位,将是:

start_sample        | end_sample          | MAX(simultaneous_people) | MAX(simultaneout_event)
2015-12-12 08:00:00 | 2015-12-12 08:59:59 | 3                        | 1
2015-12-12 09:00:00 | 2015-12-12 09:59:59 | 4                        | 2
2015-12-12 10:00:00 | 2015-12-12 10:59:59 | 4                        | 2
2015-12-12 11:00:00 | 2015-12-12 11:59:59 | 4                        | 2
2015-12-12 12:00:00 | 2015-12-12 12:59:59 | 2                        | 1
2015-12-12 13:00:00 | 2015-12-12 13:59:59 | 4                        | 2
2015-12-12 14:00:00 | 2015-12-12 14:59:59 | 1                        | 1
...

但是如果我需要将粒度更改为几天,使用此数据,我将获得

start_sample        | end_sample          | MAX(simultaneous_people) | MAX(simultaneout_event)
2015-12-12 00:00:00 | 2015-12-12 23:59:59 | 4                        | 2
2015-12-13 00:00:00 | 2015-12-12 23:59:59 | 0                        | 0
...

1 个答案:

答案 0 :(得分:0)

解决方案比我想象的要容易(希望直到现在看来都是正确的)。 我将使用我的日历生成器添加一些额外的边界,以避免我的最终数据出现空洞(没有条目的一天将不会显示):

                       ...
                       UNION 
                       SELECT @start 
                       UNION 
                       SELECT @end 
                       UNION
                           SELECT DATE_SUB(@date, INTERVAL @num:=@num+@lenght MINUTE)
                           FROM 
                             mytable,
                             (SELECT @num:=0) num
                           LIMIT 10
                       ...

然后我必须按照date_part(在postgres中)ora DATE_FORMAT(在MySQL中)进行分组,对我来说更有趣(我必须添加一个与@length配对的变量),而不是像以前那样整个边界,外部查询将变为:

SELECT Max(simultaneous_people), 
       Max(simultaneous_event), 
       DATE_FORMAT(boundary,'%Y%m%d')
FROM (...) as t
GROUP BY DATE_FORMAT(boundary,'%Y%m%d');

我希望这可能对其他人有所帮助,需要一段时间才能达到这一点。 这个查询对于大量数据来说非常繁重,因此对数据进行剪切/分段越多(垂直和水平),它的执行效果就越好,&#39; WHERE row_status = 1&#39;应该在工会获得约束的任何地方添加。