子查询
查询里套查询->WHERE子查询->计算字段子查询
什么是子查询
一句话:查询里套查询。
比如"找出工资比平均工资高的人"——你得先知道平均工资是多少,再拿它去比较。这就是两个步骤,但可以写在一句 SQL 里:
sql
SELECT name, salary
FROM users
WHERE salary > (SELECT AVG(salary) FROM users);+--------+----------+
| name | salary |
+--------+----------+
| 李四 | 12000.00 |
| 赵六 | 15000.00 |
| 周八 | 11000.00 |
| 吴九 | 13000.00 |
+--------+----------+执行顺序:MySQL 先跑括号里的 SELECT AVG(salary) FROM users 得到 9875,再跑外层 WHERE salary > 9875。
📝 子查询总是从内往外执行。
WHERE 中的子查询
子查询最常和 WHERE 搭配,作为过滤条件的数据来源。
配合 IN
"找出和孙七在同一个城市的所有人":
sql
SELECT name, city
FROM users
WHERE city IN (
SELECT city FROM users WHERE name = '孙七'
);内层查出孙七的城市 → 北京,外层查出所有北京的人。
配合比较运算符
子查询配合 = > < 等,要求子查询只返回一个值:
sql
-- 查工资最低的人
SELECT name, salary
FROM users
WHERE salary = (SELECT MIN(salary) FROM users);SELECT MIN(salary) 返回单个值 6000,外层用 = 比较,没问题。
如果子查询返回多行,= 会报错——这时候改用 IN。
多层嵌套
子查询可以套娃(但别套太深):
sql
-- 找出比"上海最高工资"还高的人
SELECT name, city, salary
FROM users
WHERE salary > (
SELECT MAX(salary)
FROM users
WHERE city = '上海'
);内层查到上海最高工资 12000,外层找出所有工资 > 12000 的人。
作为计算字段的子查询
子查询还可以放在 SELECT 里,每一行都执行一次:
sql
SELECT name,
salary,
(SELECT AVG(salary) FROM users) AS avg_all,
salary - (SELECT AVG(salary) FROM users) AS diff
FROM users;+--------+----------+----------+-----------+
| name | salary | avg_all | diff |
+--------+----------+----------+-----------+
| 张三 | 8000.00 | 9875.000 | -1875.000 |
| 李四 | 12000.00 | 9875.000 | 2125.000 |
| 王五 | 9500.00 | 9875.000 | -375.000 |
| ... | ... | ... | ... |
+--------+----------+----------+-----------+每个人的工资和平均工资一比,差距一目了然。
子查询的注意事项
只返回单列
子查询结果给外层用的时候,通常只能返回一列:
sql
-- ✅ 返回单列
SELECT * FROM users WHERE city IN (SELECT city FROM users WHERE age > 30);
-- ❌ 返回多列会报错
SELECT * FROM users WHERE city IN (SELECT city, name FROM users);性能方面
子查询每跑一次外层,内层可能就要重新执行一遍——特别是放在 SELECT 里的子查询,每行都跑一次。
大数据量时,子查询可能变慢。很多子查询可以用 JOIN 替代(下两章讲),性能通常更好。
💡 不需过度担心,数据量小的时候(几十万行以内),子查询的性能完全可接受。
小结
子查询就是"查询里套查询",一个 SELECT 的结果作为另一个 SELECT 的输入:
- WHERE 里的子查询 — 最常见的用法,用查询结果做筛选条件
- 计算字段里的子查询 — 在 SELECT 里直接查另一个表的统计数据
- 子查询的局限 — 嵌套太深可读性差,大量数据时性能不如 JOIN
- 能用 JOIN 的也能用子查询 — 选读起来更清晰的那个
💡 子查询不难,关键是搞清楚"外层查什么、内层查什么"。下一章 JOIN 会让你在两者之间多一个选择。
自主练习
- 查所有工资高于公司平均工资的人
- 查和赵六年龄相同的人(排除赵六自己)
- 查所有工资低于上海最高工资的人
- 在 SELECT 里用子查询,显示每人工资与公司最低工资的差值