sql中子查询的基本语法结构_mysql嵌套查询入门

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

子查询在 MySQL 中不是“可选技巧”,而是解决多表逻辑依赖的刚需手段。只要需要基于某次查询结果再做筛选、计算或关联,就绕不开它。

子查询必须用括号包裹,且不能加 LIMIT

MySQL 要求所有子查询必须用

()
明确包裹,否则直接报错
ERROR 1064
。另外,子查询内部不能直接使用
LIMIT
(除非配合
ORDER BY
且位于派生表位置)。

✅ 正确:
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 100)
❌ 错误:
SELECT * FROM users WHERE id IN SELECT user_id FROM orders LIMIT 10
(缺括号 + 多余 LIMIT)
⚠️ 特殊可用:
SELECT * FROM (SELECT * FROM logs ORDER BY ts DESC LIMIT 5) AS recent
(仅限 FROM 子句中的派生表)

WHERE 中的标量子查询必须返回单值

当子查询出现在

WHERE
条件右侧(如
=
>
BETWEEN
等)时,它必须只返回一行一列,即“标量”。否则会触发
ERROR 1242: Subquery returns more than 1 row

MAX()
/
MIN()
/
AVG()
聚合确保单值:
WHERE salary > (SELECT AVG(salary) FROM employees)
LIMIT 1
强制截断(慎用,语义可能不严谨):
WHERE dept_id = (SELECT id FROM departments WHERE name = 'HR' LIMIT 1)
避免写成:
WHERE status = (SELECT status FROM audits WHERE ref_id = 123)
(若有多条 audit 记录就崩)

IN 和 EXISTS 的语义与性能差异很实际

IN
检查值是否在结果集中,适合子查询结果集小、主表大;
EXISTS
是半连接语义,只关心是否存在匹配行,适合子查询结果集大、或需关联外层字段时。

SELECT name FROM customers c
WHERE EXISTS (
  SELECT 1 FROM orders o WHERE o.customer_id = c.id AND o.status = 'shipped'
);
IN
子查询无法引用外部表字段:
... WHERE id IN (SELECT customer_id FROM orders WHERE status = 'shipped')
(只能查全部)
EXISTS
子查询可关联外部字段(如上例中的
c.id
),这是它不可替代的关键点
若子查询结果为空,
IN
返回空集,
EXISTS
返回
FALSE
—— NULL 处理逻辑不同,会影响
NOT IN
的行为(
NOT IN
遇到 NULL 直接整个条件为 UNKNOWN)

子查询最易被忽略的其实是执行顺序:MySQL 通常先执行外层查询的驱动表,再对每一行执行子查询(相关子查询),这意味着 N×M 次扫描风险真实存在。别只盯着语法对不对,先看执行计划里的

DEPENDENT SUBQUERY
出现了几次。

相关推荐