SQL查询优化:实现无对应数据时显示0值行
嘿,这个问题我之前也碰到过——当筛选范围内某个分组没有匹配数据时,默认的GROUP BY会直接丢掉这一行,但我们确实需要它显示出来并填充0值。给你两种实用的优化方案,按需选择就行:
方案一:固定分组列表 + 左连接(通用所有数据库)
这个思路是先构造一个包含你需要的所有分组(0和1)的临时数据集,再用左连接关联你的统计查询。这样即使某个分组在筛选后没有数据,也会保留该行,最后用COALESCE把NULL转换成0。
-- 构造固定分组(不同数据库写法略有差异) WITH fixed_groups AS ( SELECT 0 AS id FROM dual -- Oracle写法;SQL Server可换成 FROM VALUES (0), (1) UNION ALL SELECT 1 AS id FROM dual ) SELECT COALESCE(t."Count", 0) "Count", CASE fg.id WHEN 0 THEN 'Zeroes' WHEN 1 THEN 'Ones' END "Name", COALESCE(t."Num 1", 0) "Num 1", COALESCE(t."Num 2", 0) "Num 2", COALESCE(t."Num 3", 0) "Num 3" FROM fixed_groups fg LEFT JOIN ( -- 你的原统计逻辑作为子查询 SELECT id, COUNT(id) "Count", SUM(num1) "Num 1", SUM(num2) "Num 2", SUM(num3) "Num 3" FROM mytable WHERE added_date >= :FROM_DT AND added_date <= :TO_DT GROUP BY id ) t ON fg.id = t.id ORDER BY fg.id;
注意:如果是MySQL,把FROM dual去掉即可;SQL Server可以用更简洁的FROM VALUES (0), (1)来生成固定分组。
方案二:单独统计每个分组再合并(适合分组较少的场景)
如果你的分组只有0和1这两种,也可以分别统计每个分组的结果,再用UNION ALL合并。这种写法更直接,不需要子查询关联:
-- 统计Zeroes分组 SELECT COUNT(CASE WHEN id = 0 THEN 1 END) "Count", 'Zeroes' "Name", SUM(CASE WHEN id = 0 THEN num1 ELSE 0 END) "Num 1", SUM(CASE WHEN id = 0 THEN num2 ELSE 0 END) "Num 2", SUM(CASE WHEN id = 0 THEN num3 ELSE 0 END) "Num 3" FROM mytable WHERE added_date >= :FROM_DT AND added_date <= :TO_DT UNION ALL -- 统计Ones分组 SELECT COUNT(CASE WHEN id = 1 THEN 1 END) "Count", 'Ones' "Name", SUM(CASE WHEN id = 1 THEN num1 ELSE 0 END) "Num 1", SUM(CASE WHEN id = 1 THEN num2 ELSE 0 END) "Num 2", SUM(CASE WHEN id = 1 THEN num3 ELSE 0 END) "Num 3" FROM mytable WHERE added_date >= :FROM_DT AND added_date <= :TO_DT;
这里的CASE表达式会只统计对应id的数据,没有匹配时COUNT返回0,SUM因为有ELSE 0也会返回0,刚好满足你的需求。
两种方案都能实现你要的效果:当:TO_DT设为01-JAN-2018时,Zeroes行会正常显示,所有数值字段都是0,不会消失。
内容的提问来源于stack exchange,提问作者K.R.
相关产品推荐
相关产品推荐

