MySQL 日期分组 select 语句

MySQL date grouping select statement

我有一个 MySQL 8.0.23 table 具有以下架构的调用事件:

eventUID - 整数 NOT NULL

camtimestamp - MySQL 日期时间戳

方向 - 字符串 - “In”或“Out”

propUID - 整数

在单个 SELECT 语句中,我试图按小时确定过去 24 小时内有多少辆汽车“进站”和多少辆“出站”。这是我正在尝试的(还没有内置 24 小时限制)。

select camtimestamp,count(*) from events where direction ="In" and propUID = 7 group by year(camtimestamp),month(camtimestamp),day(camtimestamp),hour(camtimestamp);

这是我得到的示例。

2022-02-14 22:02:40 38
2022-02-14 21:56:56 15
2022-02-14 20:55:30 47
2022-02-14 19:59:18 51
2022-02-14 18:59:50 36
2022-02-14 17:52:04 10
2022-02-14 16:58:01 16
2022-02-14 15:59:00 36
2022-02-14 14:58:52 44

我还有一个名为 datehourlist 的 table,我可以用它加入我的 SELECT。

示例数据:

2019-05-01 00:00:00
2019-05-01 01:00:00
2019-05-01 02:00:00
2019-05-01 03:00:00
2019-05-01 04:00:00
2019-05-01 05:00:00
2019-05-01 06:00:00
2019-05-01 07:00:00
2019-05-01 08:00:00

还有:

mysql> select min(datehour) from datehourlist;
+---------------------+
| min(datehour)       |
+---------------------+
| 2019-05-01 00:00:00 |
+---------------------+
1 row in set (0.02 sec)

mysql> select max(datehour) from datehourlist;
+---------------------+
| max(datehour)       |
+---------------------+
| 2040-12-31 00:00:00 |
+---------------------+
1 row in set (0.02 sec)

datehourlist 包含从 2019 年 5 月 1 日到 2040 年 12 月 31 日的每个小时。

这是我真正想要的示例:

下面的第 1 列是一个四舍五入的分组时间戳(对比上面的第 1 列是一个非四舍五入的实际时间戳)

如果没有来自该小时的数据,则下面的第 1 列不会跳过该小时。

下面的第 2 列是该小时的“在”计数。

下方第 3 列是该小时的“外出”次数。

2019-05-02 06:00:00 5 10
2019-05-02 07:00:00 127 10
2019-05-02 08:00:00 0 0 
2019-05-02 09:00:00 115 10
2019-05-02 10:00:00 71 10
2019-05-02 11:00:00 147 10
2019-05-02 12:00:00 140 10

我应该使用什么 SELECT 语句来获得我需要的输出?

此外,我将如何优化 SELECT 语句?

在事件中,我有 50 万个事件并且每天增长 100 个。

预先感谢您的帮助。

感谢您这么快就给出了很好的解决方案。

SELECT dhl.datehour datehour,
       COALESCE(SUM(ev.direction = 'In'), 0) `In`,
       COALESCE(SUM(ev.direction = 'Out'), 0) `Out`
  FROM datehourlist dhl
  LEFT JOIN events  ev
       ON DATE_FORMAT(ev.camtimestamp, '%Y-%m-%d %H:00:00') = dhl.datehour
 WHERE ev.camtimestamp >= DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00') - INTERVAL 24 HOUR
   AND ev.camtimestamp <  DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00')
   AND ev.propUID = 7
 GROUP BY dhl.datehour;

首先,我们需要一个 trunc_to_hour() 函数,它接受任意 DATETIMETIMESTAMP 值并返回时间到了。就是这个。

DATE_FORMAT(camtimestamp, '%Y-%m-%d %H:00:00') 

其次,我们需要一个可以处理最近 24 小时的 WHERE 表达式。就是这个。

WHERE camtimestamp >= DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00') - INTERVAL 24 HOUR
  AND camtimestamp <  DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00')

对于示例时间戳 2021-03-14 16:04:30 这给出了以下内容。

WHERE camtimestamp >= `2021-03-13 16:00:00`
  AND camtimestamp <  '2021-03-14 16:00:00`

即选择最近24个完整时钟小时的记录。如果您希望时间为最新,您可能需要调整此 WHERE 表达式。

第三,我们需要条件求和(对于 In 和 Out)。

directionIn 时表达式 direction = 'In' 给出 1,当 direction 是其他字符串时 0 (如 Out),如果 direction 本身为 NULL,则为 NULL。所以

   SUM(direction='In') 

计算满足该标准的行数。

第四,当SUM为空时,我们要显示零。像这样。

   COALESCE(SUM(direction='In'),0)

第五,我们可以像这样把它放在一起:

SELECT DATE_FORMAT(ev.camtimestamp, '%Y-%m-%d %H:00:00') datehour,
       COALESCE(SUM(ev.direction = 'In'), 0) `In`,
       COALESCE(SUM(ev.direction = 'Out'), 0) `Out`
  FROM events ev
 WHERE ev.camtimestamp >= DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00') - INTERVAL 24 HOUR
   AND ev.camtimestamp <  DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00')
   AND ev.propUID = 7
 GROUP BY DATE_FORMAT(ev.camtimestamp, '%Y-%m-%d %H:00:00')

这给了你你的结果集。但如果没有这些时间的记录,它仍然可能会丢失一些时间。

那么,第六,我们可以像这样将其添加到您的 pre-existing 每小时日历 table 中:

SELECT dhl.datehour datehour,
       COALESCE(SUM(ev.direction = 'In'), 0) `In`,
       COALESCE(SUM(ev.direction = 'Out'), 0) `Out`
  FROM datehourlist dhl
  LEFT JOIN events  ev
       ON DATE_FORMAT(ev.camtimestamp, '%Y-%m-%d %H:00:00') = dhl.datehour
 WHERE ev.camtimestamp >= DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00') - INTERVAL 24 HOUR
   AND ev.camtimestamp <  DATE_FORMAT(NOW(), '%Y-%m-%d %H:00:00')
   AND ev.propUID = 7
 GROUP BY dhl.datehour

应该就可以了。 (未调试。)