【问题标题】:MySQL - Get the total amount of concurrent events for a given date rangeMySQL - 获取给定日期范围内的并发事件总量
【发布时间】:2014-12-16 21:35:25
【问题描述】:

我有一个事件表,每个事件都有给定的开始和结束日期。

CREATE TABLE dataset (    
id int(11) unsigned NOT NULL AUTO_INCREMENT,
event varchar(64) NOT NULL DEFAULT '',
valid_from date DEFAULT NULL,
valid_to date DEFAULT NULL,
PRIMARY KEY (id)
);

INSERT INTO dataset (event, valid_from, valid_to) VALUES
('Test1', '2014-12-01', '2014-12-01'),
('Test2', '2014-12-02', '2014-12-02'),
('Test3', '2014-12-03', '2014-12-03'),
('Test4', '2014-12-04', '2014-12-04'),
('Test5', '2014-12-05', '2014-12-05'),
('Test6', '2014-12-01', '2014-12-01'),
('Test7', '2014-12-01', '2014-12-07');

我需要有关查询的帮助,以获取给定日期范围内的最大并发事件数。如果开始日期和结束日期相同,则使用此查询可以正常工作:

SET @d1 = '2014-12-01';
SET @d2 = '2014-12-01';
SELECT COUNT(*) as valid_events FROM dataset WHERE @d2 >= valid_from AND valid_to >= @d1;

这将返回 3,这对于匹配 Test1、Test6 和 Test7 的 12 月 1 日为真。但是,如果我扩大范围,它就会停止为我工作:

SET @d1 = '2014-12-01';
SET @d2 = '2014-12-07';
SELECT COUNT(*) as valid_events FROM dataset WHERE @d2 >= valid_from AND valid_to >= @d1;

这将返回 7,因为所有事件都与开始日期和结束日期重叠,但我希望它们仅在它们也相互重叠时才被计算在内。

            Test1 Test2 Test3 Test4 Test5 Test6 Test7  Result
2014-12-01    X                             X     X     3
2014-12-02          X                             X     2
2014-12-03                X                       X     2
2014-12-04                      X                 X     2
2014-12-05                            X           X     2
2014-12-06                                        X     1
2014-12-07                                        X     1

因此,如果我请求 12 月 1 日至 7 日之间的最大并发事件数量,我希望得到 3 而不是 7 的结果。

【问题讨论】:

  • 说,为了 StackOverflow 的用处,你能把你的答案写成答案,然后接受吗?
  • 请注意,包含所有可能日期的日历表的开销是(令人沮丧的)微不足道的!但纯粹主义者不喜欢它们,我想我能理解为什么。

标签: mysql date concurrency count


【解决方案1】:
 SELECT * FROM calendar WHERE dt BETWEEN  '2014-11-30' AND '2015-01-01';
+------------+
| dt         |
+------------+
| 2014-11-30 |
| 2014-12-01 |
| 2014-12-02 |
| 2014-12-03 |
| 2014-12-04 |
| 2014-12-05 |
| 2014-12-06 |
| 2014-12-07 |
| 2014-12-08 |
| 2014-12-09 |
| 2014-12-10 |
| 2014-12-11 |
| 2014-12-12 |
| 2014-12-13 |
| 2014-12-14 |
| 2014-12-15 |
| 2014-12-16 |
| 2014-12-17 |
| 2014-12-18 |
| 2014-12-19 |
| 2014-12-20 |
| 2014-12-21 |
| 2014-12-22 |
| 2014-12-23 |
| 2014-12-24 |
| 2014-12-25 |
| 2014-12-26 |
| 2014-12-27 |
| 2014-12-28 |
| 2014-12-29 |
| 2014-12-30 |
| 2014-12-31 |
| 2015-01-01 |
+------------+

SELECT x.dt
     , COUNT(*) total 
  FROM calendar x
  JOIN dataset y 
    ON x.dt BETWEEN y.valid_from AND y.valid_to 
 GROUP 
    BY dt;
+------------+-------+
| dt         | total |
+------------+-------+
| 2014-12-01 |     3 |
| 2014-12-02 |     2 |
| 2014-12-03 |     2 |
| 2014-12-04 |     2 |
| 2014-12-05 |     2 |
| 2014-12-06 |     1 |
| 2014-12-07 |     1 |
+------------+-------+

所以只需 ORDER BY... LIMIT - 你知道其余的

【讨论】:

    【解决方案2】:

    来自“草莓”的提示帮助我找到了一个解决方案,我最终得到的结果如下所示:

    SET @d1 = '2014-12-01';
    SET @d2 = '2014-12-07';
    
    SELECT x.selected_date, COUNT(*) total 
      FROM (
        select * from 
        (select adddate('1970-01-01',t4*10000 + t3*1000 + t2*100 + t1*10 + t0) selected_date from
        (select 0 t0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
        (select 0 t1 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
        (select 0 t2 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2,
        (select 0 t3 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3,
        (select 0 t4 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t4) v
        where selected_date between @d1 and @d2
      ) x
      JOIN dataset y 
        ON x.selected_date BETWEEN y.valid_from AND y.valid_to 
     GROUP 
        BY selected_date
     ORDER
        BY total DESC
     LIMIT 1;
    

    这基本上是他的解决方案,但不需要额外的日历表。要获取两个给定日期之间的日期列表,我使用了以下解决方案:https://stackoverflow.com/a/13814885/3342150

    谢谢

    【讨论】:

      【解决方案3】:

      在某一开始日期发生的最大并发事件数。因此,您可以通过一些连接和聚合来做到这一点:

      select d.valid_from, count(*) as numoverlaps
      from (select distinct d.valid_from from dataset d
           ) d join
           dataset d2
           on d.valid_from >= d2.valid_from and d.valid_from <= d2.valid_to
      group by d.valid_from;
      

      您可以通过添加order bylimit 来获得最大值:

      select d.*
      from (select d.valid_from, count(*) as numoverlaps
            from (select distinct d.valid_from from dataset d
                 ) d join
                 dataset d2
                 on d.valid_from >= d2.valid_from and d.valid_from <= d2.valid_to
            group by d.valid_from
           ) d
      order by numoverlaps desc
      limit 1;
      

      【讨论】:

      • 第一个查询给了我:valid_from: 2014-12-01, numoverlaps: 11 ?
      • @user3342150 。 . .我添加了最重要的group by
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多