NULL是SQL中表示缺失值的特殊标记,不参与常规比较与运算,需用IS NULL判断;三值逻辑使WHERE等子句忽略UNKNOWN结果;聚合函数自动忽略NULL,JOIN和IN子查询中NULL易导致数据静默丢失。

因为 NULL 在 SQL 里不是值,而是“缺失值”的标记——它不参与常规的逻辑比较、算术运算或聚合行为,所有基于“相等”“大小”“真假”的直觉判断都会失效。
NULL 不等于任何东西,包括它自己
SQL 中 NULL = NULL 返回的是 UNKNOWN(既不是 TRUE 也不是 FALSE),所以 WHERE col = NULL 永远查不到 NULL 数据。必须用 IS NULL 或 IS NOT NULL 来判断。
-
SELECT * FROM users WHERE age = NULL;→ 查不到 age 是 NULL 的行 -
SELECT * FROM users WHERE age IS NULL;→ 正确写法 - 同理,
age != 18会自动过滤掉 age 为 NULL 的行(因为NULL != 18是 UNKNOWN,不满足 WHERE 条件)
NULL 让布尔逻辑变成三值逻辑(TRUE/FALSE/UNKNOWN)
WHERE、HAVING、CHECK 约束只接受 TRUE 的行,FALSE 和 UNKNOWN 都被当作“不满足”。这导致很多看似合理的条件意外失效:
-
WHERE status = 'active' OR status != 'active':status 为 NULL 的行不会被选中(因为两部分都是 UNKNOWN) -
WHERE NOT (status = 'inactive'):同样跳过 NULL 行(NOT UNKNOWN 还是 UNKNOWN) - 想包含 NULL?得显式写成
status = 'active' OR status IS NULL
聚合函数和运算符对 NULL “视而不见”,但容易误读结果
COUNT(*) 统计所有行,COUNT(col) 只统计 col 非 NULL 的行;SUM、AVG、MAX/MIN 自动忽略 NULL —— 看似合理,但可能掩盖数据质量问题:
-
AVG(salary)是所有非 NULL salary 的平均值,不是“全体员工的平均薪资”(除非你确认没漏填) -
SUM(price) * quantity:只要 price 或 quantity 任一为 NULL,整个表达式就是 NULL(不是 0!) - 用
COALESCE(price, 0)或NULLIF()主动处理,别依赖默认行为
JOIN 和子查询中 NULL 容易引发“静默丢失”
ON 条件中涉及 NULL 的等值匹配(如 t1.id = t2.ref_id)永远失败,导致左表 NULL 外键对应行在 LEFT JOIN 中右表列为 NULL,但若后续加了 WHERE t2.status = 'ok',整行就彻底消失(因为 t2.status 是 NULL,条件为 UNKNOWN)。
- LEFT JOIN 后想保留左表全部行?WHERE 子句里别对右表字段做非 NULL 判断
- 子查询中
IN (SELECT col FROM t):如果子查询结果含 NULL,整个 IN 表达式返回 UNKNOWN,常导致意外空结果 - 安全写法:
col IN (SELECT col FROM t WHERE col IS NOT NULL)或改用 EXISTS










