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 的结果是 NULL,NULL AND TRUE 也是 NULL。

而 WHERE 子句只认 TRUE,NULL 被当成不满足条件。

所以只要 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 陷阱吗?评论区聊聊,一起排雷。

相关推荐
菜鸟~noob2332 分钟前
【电子战】第三季预告—波武器与电子系统强力毁伤
开发语言·数据库·matlab·电子战
惊讶的猫1 小时前
工具选对之后还不够:商城 Agent 的参数与权限治理
开发语言·python
cmpxr_1 小时前
【MicroPython】如何刷新ESP8266的固件
开发语言·micropython
搭贝1 小时前
上厕所的时间搭好一套系统:AI自动生成实测
开发语言·人工智能·低代码·ai·php·搭贝
智感子2 小时前
智能称重·数据上云:从仪表读数到可追溯的计量凭证
开发语言·php
Seraphina362 小时前
SQL注入(二)盲注
网络·数据库·经验分享·笔记·sql
\光辉岁月/2 小时前
7.javase-面向对象
java·开发语言
weixin_531094692 小时前
heap_4内存管理
java·开发语言·算法
疯狂的维修2 小时前
关于用C#写电机起保停控制
开发语言·c#
geovindu3 小时前
rust: Abstract Factory pattern
开发语言·后端·设计模式·rust·抽象工厂模式