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

1次阅读

子查询必须用括号包裹,否则报Error 1064;where等子句中子查询仅允许返回单列,多列报error 1241;含NULL时in失效,应改用exists;update/delete中不可直接引用目标表,需用派生表绕过。

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

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

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 中的子查询只能返回单列,多列会报错

WHEREHAVINGON 子句里使用子查询时,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)
  • 若需多字段关联,改用 JOINEXISTS(见下一条)

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 禁止在 UPDATEDELETE 的子查询中直接读取正在修改的同一张表,否则报 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 处理逻辑——它们不会像函数调用那样“先算完再代入”,而是在每行外层数据上动态执行,并受当前行上下文影响。

text=ZqhQzanResources