本章要回答的三个问题:一个查询的结果怎么喂给另一个查询——子查询能落在哪几个位置、各自要求返回什么形状?IN 和 EXISTS 都能判断"在不在集合里",什么时候该用哪个、NOT IN 为什么会整体翻车?想把两张表的结果上下拼接、或取交集差集,UNION 家族怎么用才不出错?本章解决"一个 SELECT 说不完"的问题。
第 4 章末尾留过一个悬案:AVG(SUM(price)) 这种"聚合的聚合"无法直接写——想算"各分类销售额的平均值",必须先分组算出每组 SUM,再对这组结果求平均。"对查询的结果再做查询"这个朴素愿望,就是子查询存在的全部理由。更进一步,业务还常问"买过 A 又买过 B 的顾客""价格高于全店平均的书",这些问题的条件本身就是另一个查询的答案。
子查询是通往高级 SQL 的必经之路,但也是可读性崩塌的开始——嵌套到第四层的查询没人敢改。所以本章在教写法的同时反复预告第 8 章:CTE 是给子查询起名字的脚手架,学完本章你会更懂得它为什么被发明。集合运算(UNION 家族)则从另一个维度扩展查询:JOIN 是横向拼列,UNION 是纵向拼行,一横一纵凑齐了组合结果集的完整工具箱。
| 节 | 回答哪个问题 | 关键产出 |
|---|---|---|
| 6.1 子查询的四个落点 | 查询怎么套查询 | 形状规则表、派生表、相关子查询机制 |
| 6.2 IN 与 EXISTS | 在不在集合怎么判断 | 两写法对照、NOT IN 的 NULL 陷阱与三种修法 |
| 6.3 UNION 家族 | 结果怎么上下拼 | UNION 与 UNION ALL、交集差集及 MySQL 改写 |
子查询教你会写复杂查询,也让你亲身体会复杂查询的痛——这份痛感是第 8 章 CTE 的最佳广告。
子查询能套,但套三层就该收手了。第 7 章先介绍另一种"不折叠行"的聚合武器——窗口函数,它解决的是子查询解决得很别扭的排名、组内比较问题;第 8 章再给出给复杂查询搭脚手架的正解:CTE 与视图。