MySQL子查询是指在一个SQL语句内部嵌套另一个SELECT查询,被嵌套的查询称为子查询或内查询,外面的查询称为外查询。子查询可以出现在WHERE、FROM、SELECT等子句中,用来实现复杂的过滤、计算和临时结果集处理。

一、子查询的主要类型
按照返回结果的形式,子查询通常分为以下几类:
- 标量子查询:返回单行单列,可以用在比较运算符后面。
- 列子查询:返回单列多行,常配合IN、ANY、ALL使用。
- 行子查询:返回单行多列,用括号括起多个字段比较。
- 关联子查询:子查询引用了外查询的字段,逐行执行。
- 派生表:子查询出现在FROM中,充当临时表。
二、在WHERE中使用标量子查询
假设有一张员工表emp和部门表dept,想查出工资高于公司平均工资的员工:
SELECT name, salary
FROM emp
WHERE salary > (
SELECT AVG(salary)
FROM emp
);
三、列子查询与IN的使用
查出研发部门所有员工的姓名,可以先通过子查询拿到研发部门编号:
SELECT name
FROM emp
WHERE dept_id IN (
SELECT id
FROM dept
WHERE dept_name = '研发部'
);
四、关联子查询与EXISTS
关联子查询依赖外层传值,适合判断存在性。下面查出有下属的管理者:
SELECT name
FROM emp e1
WHERE EXISTS (
SELECT 1
FROM emp e2
WHERE e2.manager_id = e1.id
);
五、FROM中的派生表
派生表必须起别名,常用于先聚合再关联:
SELECT d.dept_name, t.avg_sal
FROM (
SELECT dept_id, AVG(salary) AS avg_sal
FROM emp
GROUP BY dept_id
) t
JOIN dept d ON d.id = t.dept_id;
六、SELECT中的子查询
在SELECT里放标量子查询,可以为每行补充计算字段:
SELECT name,
(SELECT dept_name FROM dept WHERE dept.id = emp.dept_id) AS dept_name
FROM emp;
七、性能与使用建议
子查询写起来直观,但不当使用会导致全表扫描。给出几点建议:
| 场景 | 建议 |
|---|---|
| IN后接大结果集 | 改用JOIN或EXISTS |
| 关联子查询慢 | 确认外部字段有索引 |
| 派生表复杂 | 考虑写成视图或临时表 |
合理运用子查询,能让SQL逻辑更清楚,也能在多数业务查询中保持良好性能。