如何实现日期范围查询返回每日数据行,含无记录日期?
如何在查询结果中包含无数据源的日期?
这个需求太常见啦——当我们要按日期做统计,但原始数据里缺了某些日期的记录时,核心思路就是先生成包含所有目标日期的完整序列,再和原始数据做左连接,最后聚合统计。下面分几种常用数据库给你具体实现方案:
1. MySQL(8.0+ 支持递归CTE)
MySQL没有内置的日期生成函数,我们可以用递归CTE造出目标日期范围:
WITH RECURSIVE date_range AS ( -- 起始日期 SELECT '2018-03-01' AS date_val UNION ALL -- 递归生成后续日期 SELECT DATE_ADD(date_val, INTERVAL 1 DAY) FROM date_range WHERE date_val < '2018-03-03' -- 结束日期 ) SELECT dr.date_val AS Date, -- 用COALESCE把NULL转为0 COALESCE(SUM(t.Amount), 0) AS Total FROM date_range dr -- 左连接原始表,匹配日期 LEFT JOIN your_table t ON DATE(t.DateAndTime) = dr.date_val GROUP BY dr.date_val ORDER BY dr.date_val;
2. PostgreSQL
PostgreSQL有generate_series函数,生成日期序列更省心:
SELECT dr.date_val AS Date, COALESCE(SUM(t.Amount), 0) AS Total -- 直接生成从起始到结束的日期序列 FROM generate_series('2018-03-01'::date, '2018-03-03'::date, '1 day'::interval) dr(date_val) LEFT JOIN your_table t ON DATE(t.DateAndTime) = dr.date_val GROUP BY dr.date_val ORDER BY dr.date_val;
3. SQL Server
用递归CTE生成日期序列,逻辑和MySQL类似:
WITH date_range AS ( SELECT CAST('2018-03-01' AS DATE) AS date_val UNION ALL SELECT DATEADD(DAY, 1, date_val) FROM date_range WHERE date_val < CAST('2018-03-03' AS DATE) ) SELECT dr.date_val AS Date, -- 用ISNULL把NULL转为0 ISNULL(SUM(t.Amount), 0) AS Total FROM date_range dr LEFT JOIN your_table t ON CAST(t.DateAndTime AS DATE) = dr.date_val GROUP BY dr.date_val ORDER BY dr.date_val OPTION (MAXRECURSION 0); -- 如果日期范围超过100天,必须加这个参数
额外注意点
- 记得把代码里的
your_table替换成你实际的表名 - 如果日期范围是动态的(比如统计最近30天),可以把起始/结束日期改成动态计算,比如MySQL用
CURDATE() - INTERVAL 29 DAY作为起始日期 - 要是
DateAndTime字段有索引,建议用t.DateAndTime >= dr.date_val AND t.DateAndTime < dr.date_val + INTERVAL 1 DAY替代DATE()函数,避免索引失效
内容的提问来源于stack exchange,提问作者Infin8Loop
相关产品推荐
相关产品推荐

