如何在SQL中返回指定时间范围的所有行,即使指定条件不存在
解决SQL中缺失月份的显示问题
嗨,作为SQL新手遇到这种缺失数据显示的问题很正常!你的核心需求是要强制展示201801到201804的所有月份,哪怕某个月份没有code='001'的记录,对吧?
原查询的问题
你原来的查询是直接过滤code='001'后再筛选月份,这会导致没有该code记录的月份直接被排除在结果之外。要实现你的期望,我们需要先生成目标范围内的所有月份列表,再和原表做左连接,这样就能保留所有月份,再对缺失的记录填充默认值。
解决方案(分数据库版本)
下面提供两种常用的实现方式,你可以根据自己使用的数据库选择:
方式一:递归CTE生成月份列表(适用于MySQL 8.0+、SQL Server、PostgreSQL)
递归CTE可以灵活生成连续的月份范围,适合范围较大的情况:
WITH target_months AS ( SELECT '201801' AS YM UNION ALL SELECT CASE WHEN RIGHT(YM,2) = '12' THEN CONCAT(LEFT(YM,4)+1, '01') ELSE CONCAT(LEFT(YM,4), LPAD(RIGHT(YM,2)+1, 2, '0')) END AS YM FROM target_months WHERE YM < '201804' ) SELECT tm.YM, COALESCE(p.code, '0') AS code, COALESCE(p.hour, 0) AS hour FROM target_months tm LEFT JOIN pod11 p ON tm.YM = p.YM AND p.code = '001' ORDER BY tm.YM;
代码说明:
target_months递归生成了201801到201804的所有月份;- 左连接原表
pod11时,把code='001'放在连接条件里(而非WHERE子句),确保不过滤掉没有匹配的月份; COALESCE函数会把NULL值替换成你需要的默认值(code替换为'0',hour替换为0)。
方式二:数字表生成月份列表(适用于MySQL 5.x等不支持CTE的版本)
如果你的数据库不支持递归CTE,可以用简单的数字子查询生成目标月份:
SELECT ym_list.YM, COALESCE(p.code, '0') AS code, COALESCE(p.hour, 0) AS hour FROM ( SELECT CONCAT('2018', LPAD(n, 2, '0')) AS YM FROM ( SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 ) nums ) ym_list LEFT JOIN pod11 p ON ym_list.YM = p.YM AND p.code = '001' ORDER BY ym_list.YM;
代码说明:
- 内层子查询生成1-4的数字,通过
CONCAT和LPAD拼接成201801到201804的月份; - 后续的左连接和默认值填充逻辑和方式一一致。
执行以上任意一种查询,就能得到你期望的结果:
YM code hour ---------------- 201801 001 112 201802 001 64 201803 0 0 201804 0 0
内容的提问来源于stack exchange,提问作者Slavce
相关产品推荐
相关产品推荐

