mysql子查询怎么写_mysql嵌套查询实战

来源:这里教程网 时间:2026-02-28 20:53:17 作者:

子查询必须用括号包住,否则直接报错

MySQL 要求所有子查询必须出现在圆括号中,哪怕它只是

SELECT
语句的一部分。不加括号会触发
ERROR 1064 (42000)
:语法错误。

WHERE id IN (SELECT user_id FROM logs)
✅ 正确
WHERE id IN SELECT user_id FROM logs
❌ 报错
相关子查询也一样:
WHERE salary > (SELECT AVG(salary) FROM employees e2 WHERE e2.dept = e1.dept)

WHERE 中的子查询只能返回单列,多列会报错

WHERE
HAVING
ON
子句里使用子查询时,MySQL 只允许它返回**一列**(即使你只用其中一列)。如果子查询写了
SELECT name, id FROM users
,哪怕外层只比对
id
,也会报
ERROR 1241 (21000): Operand should contain 1 column(s)

正确写法:
WHERE dept_id IN (SELECT id FROM departments WHERE active = 1)
错误写法:
WHERE dept_id IN (SELECT id, name FROM departments)
若需多字段关联,改用
JOIN
EXISTS
(见下一条)

EXISTS 比 IN 更适合检查存在性,尤其子查询结果可能含 NULL

IN
判断“是否存在某记录”时,如果子查询结果包含
NULL
,整个条件会恒为
UNKNOWN
,导致查不到任何数据——这是隐式类型转换和三值逻辑惹的祸。

SELECT * FROM orders WHERE customer_id IN (SELECT id FROM customers WHERE city = 'Beijing')
—— 若子查询返回
(1, 2, NULL)
,整条
IN
判断失效
SELECT * FROM orders WHERE EXISTS (SELECT 1 FROM customers WHERE customers.id = orders.customer_id AND city = 'Beijing')
—— 不受
NULL
影响,语义更清晰
EXISTS
通常也更快,因为找到第一条匹配就停止扫描

UPDATE / DELETE 不能直接引用目标表,得用派生表绕过

MySQL 禁止在

UPDATE
DELETE
的子查询中直接读取正在修改的同一张表,否则报
ERROR 1093 (HY000): You can't specify target table 'xxx' for update in FROM clause

错误示例:
DELETE FROM users WHERE id IN (SELECT id FROM users WHERE created_at 
正确解法:把子查询包装成派生表(即加一层
SELECT * FROM (...) AS tmp
):
DELETE FROM users WHERE id IN (SELECT id FROM (SELECT id FROM users WHERE created_at 
注意别名
AS tmp
是必需的,MySQL 8.0+ 仍要求显式别名

实际写嵌套查询时,最易被忽略的是子查询的执行时机和 NULL 处理逻辑——它们不会像函数调用那样“先算完再代入”,而是在每行外层数据上动态执行,并受当前行上下文影响。

相关推荐