首页/数据/SQL 速查/NOT IN 的 NULL 陷阱

NOT IN 的 NULL 陷阱

NOT IN 对包含 NULL 的集合几乎总是返回空结果:因为 x <> NULL 是 UNKNOWN。识别与改写它是排查“查询莫名没数据”的高频问题。

SQL 速查数据更新于 2026-10-12

复现

复现
SELECT * FROM t WHERE id NOT IN (1, 2, NULL);
-- 结果为空:id <> NULL 为 UNKNOWN,不满足 WHERE

SELECT * FROM t WHERE id NOT IN (SELECT user_id FROM blacklist);
-- blacklist.user_id 若存在 NULL,同样整体为空

改写

改写
SELECT * FROM t
WHERE NOT EXISTS (
        SELECT 1 FROM blacklist b WHERE b.user_id = t.id
      );
子查询列可空时 NOT IN 语义被 NULL 破坏,生产 SQL 优先 NOT EXISTS 或先过滤 IS NOT NULL。

易错点

  • 排查时先确认子查询列是否有 NULL:SELECT COUNT(*) FROM (SELECT ...) x WHERE col IS NULL
  • NOT EXISTS 需要连接键上有索引才不会退化为逐行扫描,改写后用 EXPLAIN 确认

数据来源与参考

  • MySQL 8.0 Reference Manual · Subqueries · NULL Handling
  • PostgreSQL Documentation · Subquery Expressions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌