子查询不传递参数,相关子查询通过外层字段引用实现逐行过滤,非相关子查询则将多条件内聚于子查询中;需注意标量限制、NULL影响、性能优化及三值逻辑陷阱。

子查询本身不“传递参数”,而是通过字段引用或嵌套逻辑把条件带进去;真要跨层过滤多个条件,得看你是想在子查询里用外层字段(相关子查询),还是让子查询自己筛出满足多条件的单列结果(非相关子查询)。
相关子查询:用外层字段当“条件变量”
当你需要“对主表每一行,都去子表查是否满足某几个条件”,就得写相关子查询——子查询里直接引用主查询的字段,数据库会为每一行重新执行一次子查询。
- 必须把关联字段写在子查询的
WHERE里,比如WHERE o.user_id = u.id AND o.status = 'shipped' AND o.amount > 100 -
SELECT列只能是标量(单值),不能返回多行或多列,否则报错Subquery returns more than one row - 别在子查询
SELECT列里写主表字段,比如SELECT u.name是非法的;它只负责返回一个判断依据(如1、COUNT(*)或某个值) - 性能敏感场景慎用:如果主表有 10 万行,子查询就执行 10 万次,没索引会极慢
非相关子查询:所有条件压进子查询内部
如果你只是想“先算出一批满足多条件的 ID,再用它们去主表过滤”,那就该把全部条件写死在子查询里,外层只做 IN 或 EXISTS 匹配。
- 子查询必须只
SELECT一列,比如SELECT user_id FROM orders WHERE status = 'paid' AND created_at > '2026-07-01' - 如果子查询结果可能含
NULL,IN会整体失效,务必加AND user_id IS NOT NULL或改用EXISTS - 避免重复值干扰逻辑:用
DISTINCT或GROUP BY确保结果干净,尤其涉及JOIN时 - 大表 + 多条件组合时,
EXISTS通常比IN更快、更安全,写法是EXISTS (SELECT 1 FROM ... WHERE ...)
多条件组合匹配:别硬拼多个 IN
想表达“用户既在 A 表又在 B 表还满足 C 条件”,不是写三个 IN 堆在一起,而是用 JOIN 或 EXISTS 套嵌套。
- 错误写法:
WHERE id IN (SELECT ...) AND id IN (SELECT ...) AND id IN (SELECT ...)—— 可读性差、性能低、NULL 一出现全挂 - 正确思路:用
EXISTS分层写,每层对应一个条件块,例如EXISTS (SELECT 1 FROM a WHERE a.uid = u.id AND ...)和EXISTS (SELECT 1 FROM b WHERE b.uid = u.id AND ...) - 如果必须用
IN合并多个来源,用UNION ALL拼子查询,但所有子查询必须单列、同类型、不含NULL - 注意字段顺序和类型:像
(a, b) IN ((1,'x'),(2,'y'))这种写法要求左右两边字段数、顺序、类型完全一致,否则隐式转换可能让索引失效
最常被忽略的是 NULL 对 IN 的静默破坏——哪怕子查询只有一行是 NULL,整个条件就变 UNKNOWN,结果集为空。这不是 bug,是 SQL 三值逻辑的必然表现,处理前必须心里有数。










