咨询:为何无法对SELECT列表中使用CASE的字段执行GROUP BY
为什么没法对SELECT里的CASE字段执行GROUP BY?
嘿,这个问题的核心其实是SQL的执行顺序在搞鬼,我给你掰扯清楚哈!
首先你得明白,SQL不是按你写代码的顺序(SELECT→FROM→GROUP BY)来执行的,实际流程是这样的:
- 先执行
FROM和JOIN,把所有关联表的数据拉出来拼成临时数据集 - 然后跑
WHERE过滤数据 - 接着按
GROUP BY指定的字段把数据分组 - 之后才会计算
COUNT()这类聚合函数,再处理SELECT里的字段(包括你的CASE表达式)
你原来的CASE表达式是这么写的:
CASE WHEN COUNT(AB9_NUMOS) = 0 THEN 'P' ELSE 'E' END AS result
这里的COUNT(AB9_NUMOS)是聚合函数,它是在GROUP BY分组完成后才计算出来的结果。也就是说,当SQL执行到GROUP BY步骤的时候,这个result字段的值还根本没生成呢!你当然没法用一个还不存在的值来分组啦。
那怎么解决呢?关键是把result的判断逻辑提前到分组前完成,也就是不要依赖聚合后的结果。
看你的需求:COUNT(AB9_NUMOS)=0其实就是左连接AB9010后没有匹配到任何记录,我们可以用EXISTS来判断单条AB6记录是否有对应的AB9数据,这样就能在分组前得到result的值了。
给你两种可行的修改方案:
方案1:用CTE预处理数据
先把每条记录的result值算好,再分组统计:
WITH preprocessed_data AS ( SELECT -- 用EXISTS判断是否有匹配的AB9记录,提前得到result CASE WHEN EXISTS ( SELECT 1 FROM AB9010 WHERE AB9_FILIAL = AB6_FILIAL AND AB9_NUMOS = AB6_NUMOS + '01' AND AB9010.D_E_L_E_T_ = ' ' ) THEN 'E' ELSE 'P' END AS result, AAG_DESCRI, AB6_STATUS FROM AB6010 LEFT JOIN AB7010 ON AB7_FILIAL = AB6_FILIAL AND AB7_NUMOS = AB6_NUMOS AND AB7010.D_E_L_E_T_ = ' ' LEFT JOIN AAG010 ON AAG_CODPRB = AB7_CODPRB AND AAG010.D_E_L_E_T_ = ' ' ) SELECT result, AAG_DESCRI, COUNT(AB6_STATUS) AS count FROM preprocessed_data GROUP BY result, AAG_DESCRI;
方案2:直接在GROUP BY里重复CASE逻辑
如果不想用CTE,也可以把相同的CASE逻辑直接写到GROUP BY里(虽然有点重复,但逻辑是通的):
SELECT CASE WHEN EXISTS ( SELECT 1 FROM AB9010 WHERE AB9_FILIAL = AB6_FILIAL AND AB9_NUMOS = AB6_NUMOS + '01' AND AB9010.D_E_L_E_T_ = ' ' ) THEN 'E' ELSE 'P' END AS result, AAG_DESCRI, COUNT(AB6_STATUS) AS count FROM AB6010 LEFT JOIN AB7010 ON AB7_FILIAL = AB6_FILIAL AND AB7_NUMOS = AB6_NUMOS AND AB7010.D_E_L_E_T_ = ' ' LEFT JOIN AAG010 ON AAG_CODPRB = AB7_CODPRB AND AAG010.D_E_L_E_T_ = ' ' GROUP BY CASE WHEN EXISTS ( SELECT 1 FROM AB9010 WHERE AB9_FILIAL = AB6_FILIAL AND AB9_NUMOS = AB6_NUMOS + '01' AND AB9010.D_E_L_E_T_ = ' ' ) THEN 'E' ELSE 'P' END, AAG_DESCRI;
这样修改后,result的判断是基于单条记录的存在性,在分组前就能确定,所以GROUP BY就能正常使用这个字段啦!
内容的提问来源于stack exchange,提问作者Mário Garcia
相关产品推荐
相关产品推荐

