Oracle SQL WITH子句分组报表结果异常,求正确实现方案
问题分析与解决
问题原因
- 笛卡尔积导致结果行数爆炸:最后一步直接
select * from EvaNamP, EvaNamE, LvsSrvE是无关联的交叉连接,结果行数是三个子查询结果的乘积,这就是出现3000+行而非预期240行的核心原因。 - 分组逻辑错误:子查询中分组字段用了
AnwNamMld,但你要统计的是截取后的UserName,如果同一个UserName对应不同的AnwNamMld,会被拆分成多个分组,既导致统计结果不准确,也会增加后续交叉连接的行数。 - 日期筛选逻辑缺陷:
to_char(dzins, 'DD.MM') = to_char(sysdate - 1, 'DD.MM')会匹配所有年份中同月同日的数据,而非仅前一天的数据,应该用日期截断或范围判断实现精准筛选。
正确实现方式
方式一:条件聚合(推荐,性能更优)
直接在筛选后的数据集上按UserName分组,用count(case when ...)分别统计三类错误的数量,无需拆分多个子查询:
WITH evt AS ( SELECT substr(AnwNamMld, instr(AnwNamMld, '/') + 1) AS UserName, evanam FROM evt_t WHERE trunc(dzins) = trunc(sysdate - 1) -- 精准筛选前一天数据 ) SELECT UserName, COUNT(CASE WHEN evanam = 'EvaNamP' THEN 1 END) AS EvaNamP, COUNT(CASE WHEN evanam = 'EvaNamE' THEN 1 END) AS EvaNamE, COUNT(CASE WHEN evanam = 'LvsSrvE' THEN 1 END) AS LvsSrvE FROM evt GROUP BY UserName ORDER BY UserName;
方式二:子查询全外关联
如果坚持用多个子查询拆分统计,需要通过UserName做全外关联,确保每个用户只输出一行:
WITH evt AS ( SELECT * FROM evt_t WHERE trunc(dzins) = trunc(sysdate - 1) ), EvaNamP AS ( SELECT COUNT(*) AS EvaNamP, substr(AnwNamMld, instr(AnwNamMld, '/') + 1) AS UserName FROM evt WHERE evanam = 'EvaNamP' GROUP BY substr(AnwNamMld, instr(AnwNamMld, '/') + 1) -- 直接按目标UserName分组 ), EvaNamE AS ( SELECT COUNT(*) AS EvaNamE, substr(AnwNamMld, instr(AnwNamMld, '/') + 1) AS UserName FROM evt WHERE evanam = 'EvaNamE' GROUP BY substr(AnwNamMld, instr(AnwNamMld, '/') + 1) ), LvsSrvE AS ( SELECT COUNT(*) AS LvsSrvE, substr(AnwNamMld, instr(AnwNamMld, '/') + 1) AS UserName FROM evt WHERE evanam = 'LvsSrvE' GROUP BY substr(AnwNamMld, instr(AnwNamMld, '/') + 1) ) SELECT COALESCE(p.UserName, e.UserName, s.UserName) AS UserName, NVL(p.EvaNamP, 0) AS EvaNamP, NVL(e.EvaNamE, 0) AS EvaNamE, NVL(s.LvsSrvE, 0) AS LvsSrvE FROM EvaNamP p FULL OUTER JOIN EvaNamE e ON p.UserName = e.UserName FULL OUTER JOIN LvsSrvE s ON COALESCE(p.UserName, e.UserName) = s.UserName ORDER BY UserName;
关键优化说明
- 日期筛选改用
trunc(dzins) = trunc(sysdate - 1),确保只匹配前一天的数据,避免跨年份无效匹配。 - 分组时直接使用截取后的
UserName作为分组字段,保证同一用户的统计结果合并为一行。 - 关联查询使用
FULL OUTER JOIN配合NVL/COALESCE,确保即使某用户没有某类错误,也能显示0而非丢失该行。
内容的提问来源于stack exchange,提问作者Mik
相关产品推荐
相关产品推荐

