You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL按小时分组并将缺失小时补0的实现方法

如何补全日志小时分组中的缺失时段(统计值设为0)

这个需求太常见了——要确保按小时分组的结果里,0到23点每小时都有记录,哪怕对应时段没有数据。核心思路很简单:先生成一个包含0-23所有小时的完整时间序列,再和你的业务数据做左连接,把缺失的统计值补为0。

下面针对主流数据库给出具体解决方案:

1. PostgreSQL 实现

PostgreSQL 自带 generate_series 函数,可以快速生成连续的小时序列:

WITH hours AS (
  SELECT generate_series(0,23) AS hourr
)
SELECT 
  COALESCE(COUNT(cr.created_date), 0) AS count,
  h.hourr
FROM hours h
LEFT JOIN client_requests cr
  ON EXTRACT(HOUR FROM cr.created_date) = h.hourr
  -- 把日期过滤条件放在JOIN里,避免左连接被转为内连接
  AND cr.created_date >= '2020-02-24 00:00:00' 
  AND cr.created_date < '2020-02-25 00:00:00' -- 用小于次日0点更严谨,覆盖毫秒级数据
GROUP BY h.hourr
ORDER BY h.hourr ASC;

2. MySQL 实现

MySQL 8.0+ 支持递归CTE,低版本可以手动枚举小时:

递归CTE方式(MySQL 8.0+)

WITH RECURSIVE hours AS (
  SELECT 0 AS hourr
  UNION ALL
  SELECT hourr + 1 FROM hours WHERE hourr < 23
)
SELECT 
  COALESCE(COUNT(cr.created_date), 0) AS count,
  h.hourr
FROM hours h
LEFT JOIN client_requests cr
  ON HOUR(cr.created_date) = h.hourr
  AND cr.created_date >= '2020-02-24 00:00:00' 
  AND cr.created_date < '2020-02-25 00:00:00'
GROUP BY h.hourr
ORDER BY h.hourr ASC;

手动枚举方式(兼容所有MySQL版本)

SELECT 
  COALESCE(COUNT(cr.created_date), 0) AS count,
  h.hourr
FROM (
  SELECT 0 AS hourr UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL
  SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL
  SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL
  SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15 UNION ALL
  SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18 UNION ALL SELECT 19 UNION ALL
  SELECT 20 UNION ALL SELECT 21 UNION ALL SELECT 22 UNION ALL SELECT 23
) h
LEFT JOIN client_requests cr
  ON HOUR(cr.created_date) = h.hourr
  AND cr.created_date >= '2020-02-24 00:00:00' 
  AND cr.created_date < '2020-02-25 00:00:00'
GROUP BY h.hourr
ORDER BY h.hourr ASC;

3. SQL Server 实现

可以用递归CTE或系统表生成小时序列:

递归CTE方式

WITH RECURSIVE hours AS (
  SELECT 0 AS hourr
  UNION ALL
  SELECT hourr + 1 FROM hours WHERE hourr < 23
)
SELECT 
  COALESCE(COUNT(cr.created_date), 0) AS count,
  h.hourr
FROM hours h
LEFT JOIN client_requests cr
  ON DATEPART(HOUR, cr.created_date) = h.hourr
  AND cr.created_date >= '2020-02-24 00:00:00' 
  AND cr.created_date < '2020-02-25 00:00:00'
GROUP BY h.hourr
ORDER BY h.hourr ASC;

关键注意点

  • 日期过滤条件放JOIN子句:如果放在WHERE里,左连接后无匹配的记录会被过滤,失去补0效果。
  • 用COALESCE处理NULL:左连接后无数据的小时,COUNT(cr.created_date) 会返回NULL,需要用COALESCE转为0。
  • 日期范围严谨性:用< '次日0点'代替< '当日23:59:59',可以覆盖毫秒级的时间数据(比如23:59:59.999)。

内容的提问来源于stack exchange,提问作者Abdusoli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 20:07:53