三值逻辑是SQL处理NULL的必然机制,导致WHERE中= NULL、!=、NOT IN等操作静默过滤NULL行;正确写法需用IS NULL、NOT EXISTS或显式补NULL判断。

三值逻辑不是SQL的bug,而是NULL参与运算时的必然结果。只要WHERE条件里出现任何与NULL的比较(比如 =、!=、IN、NOT IN),就可能把本该返回的行静默过滤掉——不报错、不警告、只少数据。
WHERE中用= NULL或!= 100为什么查不到NULL行
因为= NULL永远返回UNKNOWN,而WHERE只保留TRUE行。UNKNOWN和FALSE一样被丢弃。同理,score != 100对score IS NULL的行也返回UNKNOWN,所以这些行不会出现在结果里。
- 错误写法:
WHERE status = NULL→ 永远无匹配 - 正确写法:
WHERE status IS NULL - 想同时抓
!= 100和NULL?得显式补上:WHERE score != 100 OR score IS NULL
NOT IN子查询一有NULL就整个失效
假设你写id NOT IN (SELECT manager_id FROM staff),只要子查询里任意一个manager_id是NULL,整条NOT IN表达式就恒为UNKNOWN,主查询结果为空。
- 根本原因:
id NOT IN (1, 2, NULL)等价于id != 1 AND id != 2 AND id != NULL,最后一项是UNKNOWN,整条逻辑变成UNKNOWN - 安全替代:
NOT EXISTS (SELECT 1 FROM staff s WHERE s.manager_id = t.id) - 如果非用
NOT IN,必须先排除NULL:NOT IN (SELECT manager_id FROM staff WHERE manager_id IS NOT NULL)
CASE WHEN里WHEN NULL永远不命中
简单CASE(CASE col WHEN value THEN)底层会做col = value比较,所以WHEN NULL实际执行的是col = NULL → UNKNOWN → 不走这个分支。
- 错误写法:
CASE status WHEN NULL THEN 'missing' ELSE 'ok' END - 正确写法(搜索型CASE):
CASE WHEN status IS NULL THEN 'missing' ELSE 'ok' END - 聚合函数也受此影响:
COUNT(status)跳过NULL,但COUNT(*)统计所有行,别混用
最易被忽略的点是:三值逻辑不只影响WHERE,它渗透在JOIN结果字段参与计算(如price * 1.1遇到NULL直接得NULL)、ORDER BY排序(NULL通常排最前或最后,且不同数据库行为不一致)、甚至索引是否生效(含NULL的列,B-Tree索引可能无法高效定位)——这些地方都得主动防御,不能靠“看起来应该没问题”。

















