MySQL 子查询
子查询是嵌套在其他 SQL 语句中的 SELECT 查询,用于实现复杂的条件过滤和数据获取。
分类概述
| 类型 | 位置 | 返回结果 |
|---|---|---|
| 标量子查询 | SELECT/WHERE/HAVING | 单个值 |
| 列子查询 | WHERE | 单列多值 |
| 行子查询 | WHERE | 单行多列 |
| 表子查询 | FROM | 多行多列 |
标量子查询
返回单个值,可出现在 SELECT、WHERE、HAVING 子句中。
SQL
-- 查询薪资高于平均值的员工
SELECT emp_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
-- SELECT 子句中使用
SELECT emp_name,
(SELECT dept_name FROM departments d WHERE d.dept_id = e.dept_id) AS dept_name
FROM employees e;
列子查询
返回单列多值,配合 IN、ANY、ALL 操作符使用。
SQL
-- IN:匹配列表中任意值
SELECT * FROM employees
WHERE dept_id IN (SELECT dept_id FROM departments WHERE location = '北京');
-- ANY:满足列表中任一条件
SELECT * FROM employees
WHERE salary > ANY (SELECT salary FROM employees WHERE dept_id = 10);
-- ALL:满足列表中所有条件
SELECT * FROM employees
WHERE salary > ALL (SELECT salary FROM employees WHERE dept_id = 10);
行子查询
返回单行多列,用于完整行比较。
SQL
-- 查询与某员工同部门同职位的员工
SELECT * FROM employees
WHERE (dept_id, job_id) = (SELECT dept_id, job_id FROM employees WHERE emp_id = 100);
-- 使用行构造器比较
SELECT * FROM employees
WHERE (salary, hire_date) > (SELECT MAX(salary), MIN(hire_date) FROM employees);
表子查询(派生表)
返回多行多列,放在 FROM 子句中作为临时表使用。
SQL
-- 派生表必须起别名
SELECT dept_name, avg_salary
FROM (
SELECT d.dept_name, AVG(e.salary) AS avg_salary
FROM departments d
JOIN employees e ON d.dept_id = e.dept_id
GROUP BY d.dept_id, d.dept_name
) AS dept_stats
WHERE avg_salary > 5000;
-- 配合 EXISTS 使用
SELECT emp_name FROM employees e
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.emp_id = e.emp_id AND o.order_date > '2026-01-01'
);
相关子查询
子查询引用外部查询的字段,每行执行一次。
SQL
-- 查询各部门薪资最高的员工
SELECT e.emp_name, e.salary, e.dept_id
FROM employees e
WHERE salary = (
SELECT MAX(salary)
FROM employees e2
WHERE e2.dept_id = e.dept_id
);
使用建议
相关子查询性能较低,大数据量时建议改用 JOIN 实现。
SQL
-- 相关子查询改写为JOIN
SELECT e.emp_name, e.salary, e.dept_id
FROM employees e
JOIN (SELECT dept_id, MAX(salary) AS max_sal FROM employees GROUP BY dept_id) m
ON e.dept_id = m.dept_id AND e.salary = m.max_sal;
要点总结
- 标量子查询返回单值,可用于任何可使用表达式的地方
- 列子查询配合 IN/ANY/ALL 操作符处理多值匹配
- 表子查询必须起别名,可作为数据源使用
- 相关子查询逐行执行,大数据量时优先考虑 JOIN 改写
📝 发现内容有误?点击此处直接编辑