子查询必须用括号,且不能在内层用 ORDER BY
MySQL 要求所有子查询必须包裹在
()中,这是语法硬性要求,漏括号会直接报错
ERROR 1064。更隐蔽的坑是:子查询内部不能写
ORDER BY——哪怕你只是想给子查询结果排个序再取 top N,MySQL 也会忽略它(除非配合
LIMIT),甚至在严格模式下直接报错。真正生效的排序必须放在最外层
SELECT的
ORDER BY中。
WHERE 里用子查询,注意操作符和结果集匹配
子查询在
WHERE子句中使用最频繁,但操作符选错会导致逻辑错误或报错: 标量子查询(返回单值,如
(SELECT AVG(salary) FROM employees))只能搭配单行操作符:
=、
>、
、<code>等 列子查询(返回一列多行,如
(SELECT product_id FROM order_items))必须用多行操作符:
IN、
NOT IN、
ANY、
ALL若误用
=去比较一个可能返回多行的子查询,MySQL 会报错
ERROR 1242: Subquery returns more than 1 row
FROM 后的子查询必须起别名,否则语法报错
当子查询出现在
FROM子句中(即当作临时表用),MySQL 强制要求给它起别名,否则报错
ERROR 1248: Every derived table must have its own alias。这个别名不是可选项,是语法必需:
SELECT s.name, t.avg_grade
FROM students s
JOIN (SELECT student_id, AVG(grade) AS avg_grade
FROM grades GROUP BY student_id) t
ON s.id = t.student_id;
注意:子查询里的列别名(如
avg_grade)对外层可见,但子查询本身那个括号块必须有表别名(如这里的
t)。
性能敏感场景慎用子查询,优先考虑 JOIN 或 EXISTS
子查询在数据量大时容易变慢,尤其当它被重复执行(相关子查询)或导致索引失效时。例如:
NOT IN (SELECT ...)遇到子查询结果含
NULL,整条语句会返回空结果(三值逻辑陷阱) 用
IN替代时,若子查询结果集较大,MySQL 可能放弃使用索引 对“是否存在”的判断,
NOT EXISTS通常比
NOT IN更快,且不惧
NULL
真实线上环境,只要涉及百万级以上表关联,建议先 explain 执行计划;如果看到
Using temporary或
Using filesort频繁出现,就得考虑把子查询重写为
JOIN或改用
EXISTS。
子查询看着简洁,但它的执行时机(先算内层)、结果复用能力、以及与索引的配合度,远不如显式
JOIN可控。写完务必看
EXPLAIN,别只信逻辑对不对。
