SQL同表关联子查询中HAVING c2.Country <> c.Country条件作用原理求解
关联子查询运行逻辑讲解
核心执行逻辑:关联子查询逐行绑定运行
这是典型的关联子查询,执行顺序和非关联子查询完全不同,不会先计算完内层再跑外层,而是按以下步骤执行:
- 先执行外层的
GROUP BY c.Country,得到所有国家对应的客户数临时结果,也就是你示例里的5行数据:cnt | Country 3 | Argentina 3 | Belgium 9 | Brazil 2 | IRAN 2 | Turkey - 外层逐行遍历这个临时结果,每一行都会把当前行的
c.Country值代入内层子查询单独执行一次:- 内层先对全表
Customers按c2.Country分组 - 用
HAVING c2.Country <> 外层当前传入的国家,把「当前外层行对应的国家」从内层分组结果里排除 - 最后返回剩下所有国家的客户数集合
- 内层先对全表
- 外层用当前行的
cnt判断是否不在内层返回的集合里,符合条件就保留该行。
用示例场景逐行验证
我们拿你给出的示例数据分别验证3种典型情况:
情况1:外层当前行是巴西(cnt=9,Country=Brazil)
代入内层后c2.Country <> c.Country等价于c2.Country <> 'Brazil',内层排除巴西分组后,剩下国家的客户数是[3,3,2,2],去重后返回集合(3,2)。
判断9 NOT IN (3,2)结果为真,所以巴西行保留。
情况2:外层当前行是阿根廷(cnt=3,Country=Argentina)
代入内层后c2.Country <> 'Argentina',内层排除阿根廷分组后,剩下国家的客户数是[3,9,2,2],返回集合(3,9,2)。
判断3 NOT IN (3,9,2)结果为假,所以阿根廷行被排除。
情况3:外层当前行是伊朗(cnt=2,Country=IRAN)
代入内层后c2.Country <> 'IRAN',内层排除伊朗分组后,剩下国家的客户数是[3,3,9,2],返回集合(3,9,2)。
判断2 NOT IN (3,9,2)结果为假,所以伊朗行被排除。
逻辑本质
这段SQL的作用就是筛选出客户数是唯一值的国家:只要某国家的客户数,在其他所有国家的客户数里没有重复出现,就会被保留。
小提示:该写法是关联子查询,每一行都要跑一次内层聚合,数据量大的时候性能较差,等价的窗口函数写法性能更优:
SELECT cnt, Country FROM ( SELECT COUNT(CustomerID) cnt, Country, COUNT(*) OVER(PARTITION BY COUNT(CustomerID)) cnt_freq FROM Customers GROUP BY Country ) t WHERE cnt_freq = 1
内容的提问来源于stack exchange,提问作者Mohi
相关产品推荐
相关产品推荐

