NOT IN 的 NULL 陷阱:一次 UNION 数据"神秘消失"

昨天写了个 SQL,逻辑明明没毛病,数据就是查不出来。排查半天,元凶竟是 NULL

一、现象:我的数据呢?

先看我写的 SQL,很简单:

SQL 复制代码
WITH tmp_union3 AS (
    SELECT * FROM tmp_union
    UNION ALL
    SELECT * FROM tmp_union2
    WHERE id NOT IN (
        SELECT DISTINCT id FROM tmp_union
    )
)
SELECT * FROM tmp_union3 WHERE id = '23009724';

已知:

  • tmp_union 里没有 '23009724'
  • tmp_union2明明有 '23009724'

按道理,NOT IN 应该放行,然后 UNION ALL 合并,最后查出来。

结果:查无此记录。

二、排查:问题出在哪?

先单独跑 NOT IN 这一段:

SQL 复制代码
SELECT * FROM tmp_union2
WHERE id NOT IN (SELECT DISTINCT id FROM tmp_union);

返回:空结果集

'23009724' 明明不在 tmp_union 里,凭啥被过滤了?

再查一下 tmp_union 的数据:

SQL 复制代码
SELECT id FROM tmp_union;

破案了------tmp_union 里有 NULL

三、原理:一个 NULL,全军覆没

在 PostgreSQL 里,没有unknown,只有null,NULL 代表"未知"

NOT IN 的右侧出现 NULL 时:

SQL 复制代码
'2026' NOT IN (NULL, '2025', '2026')

数据库实际比较:

SQL 复制代码
'2026' = '2025'  → FALSE
'2026' = NULL        → NULL   -- 不是 FALSE,是 NULL!

关键点来了:

NOT IN 的本质是 AND 串联的等值比较

Plain 复制代码
'2026' <> NULL AND '2026' <> '2025' AND ...

在 PG 里,NULL AND FALSE 的结果是 NULLNULL AND TRUE 也是 NULL

WHERE 子句只认 TRUENULL 被当成不满足条件。

所以只要 NOT IN 的右侧集合里有一个 NULL,整个条件就塌了,所有行都被过滤。

不是一个,是全部。这就是黑洞。

四、修复:三选一

方法 1:过滤 NULL(改动最小)

SQL 复制代码
WHERE id NOT IN (
    SELECT DISTINCT id FROM tmp_union
    WHERE id IS NOT NULL  -- 加这一行
)

方法 2:改用 NOT EXISTS(推荐)

SQL 复制代码
SELECT * FROM tmp_union2 t2
WHERE NOT EXISTS (
    SELECT 1 FROM tmp_union t1
    WHERE t1.id = t2.id
);

NOT EXISTS 不受 NULL 影响,而且性能通常更好。

方法 3:LEFT JOIN 取差集

SQL 复制代码
SELECT t2.*
FROM tmp_union2 t2
LEFT JOIN tmp_union t1 ON t1.id = t2.id
WHERE t1.id IS NULL;

五、口诀

看到 NOT IN,先防 NULL;能写 EXISTS,别写 IN

六、总结

这次踩坑就一句话:

NOT IN 遇到 NULL,不是漏几条,是全部消失。

而且不会报错,悄无声息。

你以为是逻辑问题,其实是 NULL 在搞鬼。

以后写 SQL,遇到 NOT IN 多长个心眼,或者直接换成 NOT EXISTS,一劳永逸。

你遇到过类似的 NULL 陷阱吗?评论区聊聊,一起排雷。

相关推荐
咖啡八杯40 分钟前
GoF设计模式——策略模式
java·后端·spring·设计模式
lizhongxuan2 小时前
AI Agent 上下文压缩利器 Headroom
后端
Csvn4 小时前
SSH 远程管理与安全加固 — 运维的守门之道
后端
IT_陈寒4 小时前
Python搞不定字符串编码?这破玩意坑我两小时!
前端·人工智能·后端
菜鸟谢5 小时前
Rust 智能指针完整详解
后端
菜鸟谢6 小时前
Rust 函数完整知识点详解
后端
爱勇宝6 小时前
淡泊名利之前,先承认我们都很焦虑
前端·后端·程序员
菜鸟谢6 小时前
Rust 闭包(Closure)完整详解
后端
ServBay6 小时前
如何利用本地技术栈构建 0 成本 AI SaaS 雏形
后端·aigc·ai编程
菜鸟谢6 小时前
Rust 集合 + 迭代器完整详解
后端