sql子查询按位置分三类:where中先算内层再筛外层,用于条件过滤;from中作临时表须起别名;select中为标量子查询,每行执行一次且限单值。执行时机依位置动态决定。

SQL子查询就是把一个查询嵌套在另一个查询里,它本身是一条完整的SELECT语句,可以出现在WHERE、FROM、SELECT甚至HAVING子句中。关键不是“怎么写”,而是“在哪写、怎么用、为什么这样执行”。下面从常用位置和执行逻辑两方面说清楚。
WHERE中的子查询:先算内层,再筛外层
这是最常见用法,用于条件过滤。子查询返回单值或一列多行结果,外层用=、IN、EXISTS等配合。
- 单值比较(标量子查询):比如SELECT name FROM student WHERE age > (SELECT AVG(age) FROM student),括号内先算出平均年龄,再拿每条学生记录去比。
- 多值匹配(IN子查询):比如SELECT * FROM order WHERE customer_id IN (SELECT id FROM customer WHERE city = '北京'),先查出所有北京客户的id列表,再筛选订单。
- 存在性判断(EXISTS):比如SELECT * FROM customer c WHERE EXISTS (SELECT 1 FROM order o WHERE o.customer_id = c.id),对每个客户,检查是否有对应订单——这里子查询不返回数据,只返回真假,且可关联外层字段(c.id)。
FROM中的子查询:当作临时表来用
必须起别名,否则语法报错。数据库会先把子查询结果生成一个虚拟表,再对外层做JOIN或过滤。
- 典型场景是分组后二次筛选,比如SELECT dept, avg_salary FROM (SELECT dept, AVG(salary) AS avg_salary FROM emp GROUP BY dept) t WHERE avg_salary > 8000。内层按部门算平均工资,外层再筛高于8000的部门。
- 注意:子查询里的字段不能直接被外层WHERE引用(作用域限制),必须通过别名t来访问。
SELECT中的子查询:给每一行加计算字段
也叫标量子查询,要求必须返回**至多一行一列**,否则运行时报错。常用来补充关联信息而不显式JOIN。
- 例如:SELECT id, name, (SELECT COUNT(*) FROM order WHERE customer_id = customer.id) AS order_count FROM customer。对每个客户,单独查一遍他的订单数,作为新列展示。
- 性能提示:这种写法可能被反复执行(每行一次),大数据量时不如LEFT JOIN + GROUP BY高效。
子查询执行流程的核心原则
不是“从左到右”或“从上到下”,而是按子查询所处的位置和类型动态决定执行时机:
- WHERE里非关联子查询:执行一次,结果缓存,后续复用;
- WHERE里关联子查询(含EXISTS):对外层每一行执行一次,可能带索引优化;
- FROM里的子查询:先完整执行,生成中间结果集,再参与外层运算;
- SELECT里的标量子查询:对结果集的每一行执行一次,无法提前终止。










