MySQL如何复用两个计算结果做二次计算及报错排查
错误原因说明
- 第一次触发
Error Code: 1248的原因:SQL中所有FROM/JOIN后面的派生表(子查询结果)必须定义独立别名,你的第一版写法中两层嵌套子查询都没有设置别名,不符合语法要求。 - 第二次触发
Error Code: 1054的原因:你虽然给两个派生表加了别名a、b,但存在两个逻辑问题:- 内层b表的查询中,只返回了
Total字段,没有把关联的a表中的OverDue字段查出来,外层查询自然无法识别这个列; - 你用INNER JOIN连接两个统计结果的写法本身就冗余,两个子查询都是返回单值的聚合结果,既没有写关联条件,也没必要做表连接,额外增加了表扫描次数。
- 内层b表的查询中,只返回了
正确实现方案
直接用条件聚合一次扫描表即可完成统计,性能更高、写法更简洁,不会出现语法问题:
SELECT CONCAT(ROUND(overdue_count / total_count * 100, 2), '%') AS Percentage_OverDue FROM ( SELECT COUNT(*) AS total_count, SUM(CASE WHEN ReturnDt > DueDt THEN 1 ELSE 0 END) AS overdue_count FROM loanlist ) AS stat;
语法说明:
- 内层子查询一次遍历
loanlist表,同时统计出总借阅记录数total_count、逾期记录数overdue_count:用CASE判断归还时间晚于应还时间的记录记为1,否则记为0,SUM求和就是逾期总条数,仅需扫描一次表,性能远高于多次查子查询再JOIN的写法。 - 外层计算占比时用
ROUND保留2位小数,拼接%让结果更直观,派生表stat设置了符合要求的别名,不会触发1248错误。
如果你一定要保留原来的子查询JOIN写法(不推荐,性能差),需要补全关联条件、在外层可访问的位置返回OverDue字段,修正后语法如下:
-- 仅作语法修正参考,不推荐生产环境使用 SELECT CONCAT(ROUND(OverDue/Total * 100, 2), '%') AS Percentage_OverDue FROM ( SELECT COUNT(*) AS Total, a.OverDue FROM loanlist INNER JOIN ( SELECT COUNT(*) AS OverDue FROM loanlist WHERE ReturnDt > DueDt ) AS a ON 1=1 -- 两个单值聚合结果用恒真条件关联 ) AS b;
注意:该写法会全表扫描
loanlist两次,数据量越大性能损耗越明显,优先选择条件聚合的方案。
内容的提问来源于stack exchange,提问作者HilalKarappan
相关产品推荐
相关产品推荐

