SQL查询未加指定筛选分组时返回多行而非预期单行的问题咨询

问题相关SQL
原始查询语句:
select t.customer_type, (case when &a1 in (1, 2) and &a2 in ('AZN', 'USD', 'ALL') then (select t.balance_no from test12 t where t.customer_type = &a1 and t.currency = &a2) when &a1 in (1, 2) and &a2 not in ('AZN', 'USD', 'ALL') then (select t.balance_no from test12 t where t.customer_type = &a1 and t.currency = 'ALL') end) from test12 t where t.customer_type = &a1 group by t.customer_type;
如果移除末尾的筛选、分组逻辑:
where t.customer_type = &a1 group by t.customer_type
查询会返回和test12表总行数一致的结果,而非预期的单行结果。核心疑问:CASE语句的子查询中已经写了t.customer_type=&a1 and t.currency=&a2的筛选条件,为什么外层不加上述逻辑就会返回全表行数的结果?
原因说明
- SQL的执行顺序是优先处理
FROM子句加载表数据,再依次处理WHERE过滤、GROUP BY分组,最后才会计算SELECT后面的字段值。外层写了from test12 t又没加WHERE过滤条件时,第一步生成的基础结果集就是test12的全量行,和SELECT里写了什么计算逻辑没有任何关系。 - 写在CASE里的子查询属于标量子查询,作用仅仅是给基础结果集里的每一行计算出一个对应的列值,既不会过滤外层的行,也不会自动合并重复行。举个最简单的例子:写
select id, (select '固定文本') from user,不管子查询返回什么固定内容,最终结果行数永远和user表的总行数一致。 - 子查询内部写的筛选条件只约束子查询自身的返回结果,完全不会影响外层FROM加载的行数。你当前写的子查询本身只会返回一个固定的balance_no值,效果等同于给全表每一行都拼上同一个固定字段值,自然会返回全表行数。
- 你额外加的两段逻辑才是控制返回行数的核心:
where t.customer_type = &a1先把外层全表数据过滤到只剩对应客户类型的行,group by t.customer_type再把同客户类型的多行合并为1行,最终才能得到你预期的单行结果。
额外注意:子查询里给test12起的别名也叫t,和外层表别名重名,虽然当前子查询没有引用外层字段不会触发关联逐行计算,但这种写法非常容易因为别名混淆写出逻辑bug,建议子查询换个不同的别名比如t_sub。
内容的提问来源于stack exchange,提问作者deku
相关产品推荐
相关产品推荐

