IS NULL、IS NOT NULL 与 NULL 安全相等
正确测试 NULL,并掌握各方言中的 NULL 安全运算符
IS NULL、IS NOT NULL 与 NULL 安全相等 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。
以正确方式检查 NULL
上一课证明了不能使用 = 查找 NULL。那么,实际应该如何检查 NULL 呢?请使用专用谓词 IS NULL 和 IS NOT NULL。
这是检查缺失值的唯一正确且可移植的方式,面试官每次看到 col = NULL 都会判定它是错误的。
本课将介绍 IS NULL、IS NOT NULL、IS DISTINCT FROM 系列,以及特定数据库方言的 NULL 安全等值运算符。了解不同数据库之间的差异,是体现资深水平的重要信号。
IS NULL 和 IS NOT NULL
当值为 NULL 时,IS NULL 返回 TRUE,否则返回 FALSE。关键在于,它永远不会返回 UNKNOWN,因此可以安全地直接用于 WHERE。
IS NOT NULL 是它的完全补集:对于任何实际值返回 TRUE,对于 NULL 返回 FALSE。
这些谓词是处理 NULL 的主力工具。它们属于标准结构化查询语言,在 MySQL、Postgres、SQL Server、Oracle 和 SQLite 中的行为完全一致。
-- Find employees with no recorded bonus
SELECT name FROM employees WHERE bonus IS NULL;
-- Find employees that do have a bonus
SELECT name FROM employees WHERE bonus IS NOT NULL;为什么列 = NULL 总是错误
这是面试中必考的陷阱:候选人写出 WHERE bonus = NULL,以为这样能找出缺失的奖金。结果是零行。
请记住三值逻辑:对于每一行,包括值为 NULL 的行,bonus = NULL 都是 UNKNOWN,因为没有任何值等于未知值。WHERE 只保留 TRUE,因此没有任何行能匹配。
某些数据库在非标准模式下会悄悄将 = NULL 改写为 IS NULL,但您绝不能依赖这种行为。请始终显式写出 IS NULL。
-- WRONG: returns zero rows, bonus = NULL is UNKNOWN for all
SELECT name FROM employees WHERE bonus = NULL;
-- RIGHT:
SELECT name FROM employees WHERE bonus IS NULL;统计 NULL 值与非 NULL 值
分析人员经常需要执行数据质量审计:某一列的数据有多完整?将 IS NULL 与 COUNT 结合起来,即可报告缺失值。
请注意二者的区别:COUNT(*) 统计每一行,而 COUNT(bonus) 只统计非 NULL 的奖金。二者之差就等于 NULL 的数量,我们将在聚合课程中再次介绍这一事实。
SELECT
COUNT(*) AS total_rows,
COUNT(bonus) AS with_bonus,
COUNT(*) - COUNT(bonus) AS missing_bonus,
SUM(CASE WHEN bonus IS NULL THEN 1 ELSE 0 END) AS missing_check
FROM employees;NULL 安全等值比较所解决的问题
假设您希望匹配两列,并将“两者都是 NULL”视为匹配。普通的 a = b 会失败:当两者都是 NULL 时,结果是 UNKNOWN,因此这对值会被排除,尽管直觉上它们是“相同的”。
在比较旧行和新行以检测变化,或根据可选列进行连接时,都会遇到这种情况。您需要一种比较方式,使NULL 等于 NULL 时结果为 TRUE,而NULL 与某个值比较时结果为 FALSE。这正是 NULL 安全等值比较提供的能力。
-- Goal: change-detection where two NULLs count as equal
-- Plain equality fails when both sides are NULL:
-- NULL = NULL -> UNKNOWN (treated as not-equal)
SELECT * FROM old_t o JOIN new_t n ON o.id = n.id
WHERE o.note = n.note; -- misses rows where both notes are NULLIS DISTINCT FROM(标准结构化查询语言)
符合 ANSI 标准的 NULL 安全比较是 IS DISTINCT FROM,其逆运算是 IS NOT DISTINCT FROM。Postgres、SQL Server(2022 及更高版本)以及其他数据库支持它们。
a IS NOT DISTINCT FROM b表示“相等,其中 NULL = NULL 也算相等”。a IS DISTINCT FROM b表示“不同,将 NULL 当作普通值处理”。
它们始终返回 TRUE 或 FALSE,从不返回 UNKNOWN,因此在任何需要谓词的地方都可以安全使用。
-- TRUE when notes match, including both NULL
SELECT * FROM old_t o JOIN new_t n ON o.id = n.id
WHERE o.note IS NOT DISTINCT FROM n.note;
-- TRUE when notes differ (NULL vs value counts as different)
SELECT * FROM old_t o JOIN new_t n ON o.id = n.id
WHERE o.note IS DISTINCT FROM n.note;MySQL 的 <=> 运算符
MySQL 提供了一种简洁的 NULL 安全等值运算符,写作 <=>(太空船运算符)。
a <=> b 在两侧相等或两侧都是 NULL 时返回 1(TRUE),否则返回 0(FALSE)。它相当于 MySQL 中的 IS NOT DISTINCT FROM。
如果面试官特别询问 MySQL 中的 NULL 安全匹配,这就是惯用答案。
-- MySQL: 1 when both equal or both NULL
SELECT (NULL <=> NULL) AS both_null, -- 1
(NULL <=> 5) AS null_vs_val, -- 0
(5 <=> 5) AS val_eq; -- 1
SELECT * FROM old_t o JOIN new_t n ON o.id = n.id
WHERE o.note <=> n.note;跨方言速查表
面试官会认可了解可移植性边界的候选人。下面是 NULL 安全相等比较对照表:
- ANSI / Postgres / SQL Server 2022+:
IS NOT DISTINCT FROM - MySQL / MariaDB:
<=> - SQLite:
IS和IS NOT可用作 NULL 安全相等比较 - Oracle:没有原生运算符;可以使用
DECODE(a, b, 1, 0) = 1或 COALESCE 技巧进行模拟
如果不确定所用的数据库引擎,请改用下一节所示的可移植手动写法。
-- SQLite NULL-safe equality
SELECT * FROM t WHERE a IS b; -- TRUE when both NULL
SELECT * FROM t WHERE a IS NOT b; -- complement可移植的手动 NULL 安全匹配
如果没有可用的原生运算符,您可以使用基本操作构建 NULL 安全的相等比较。这个可移植模式将普通相等比较与明确的两者均为 NULL 子句结合起来。
可以这样理解:“它们相等,或者它们都缺失。”这适用于所有数据库,因此当面试官没有明确指定方言时,这是很好的回答。
SELECT *
FROM old_t o JOIN new_t n ON o.id = n.id
WHERE (o.note = n.note)
OR (o.note IS NULL AND n.note IS NULL);
-- Alternative using COALESCE with a sentinel that
-- cannot occur in real data:
-- WHERE COALESCE(o.note, '##NULL##') = COALESCE(n.note, '##NULL##')深入示例:NULL 安全的 JOIN 键
一个现实中的陷阱是:使用可为 NULL 的键进行连接。如果两侧的 region 都可以为 NULL,普通等值连接会悄悄丢弃这些配对,因为 NULL = NULL 的结果是 UNKNOWN。
如果业务规则是“没有区域的行仍应与另一侧没有区域的行匹配”,您必须使 JOIN 条件具备 NULL 安全性。在面试中请明确说出这一假设,然后选择与数据库引擎相匹配的运算符。
-- Postgres / ANSI: match including both-NULL regions
SELECT a.id, b.id
FROM table_a a
JOIN table_b b
ON a.region IS NOT DISTINCT FROM b.region;
-- MySQL equivalent: ON a.region <=> b.region面试要点
要清晰应对任何 NULL 测试问题:
- 始终使用
IS NULL/IS NOT NULL;绝不要使用= NULL。 - 这些谓词只返回 TRUE 或 FALSE,因此可以安全地用于 WHERE。
- 若要实现“NULL 等于 NULL”的匹配,请使用 IS NOT DISTINCT FROM(ANSI)或 <=>(MySQL)。
- 说明您针对的是哪种方言;不确定时,提供可移植的 OR 子句回退方案。
同时说出标准运算符和厂商运算符,能展现面试筛选者会注意到的知识广度。
快速检查
请选择正确的 NULL 安全比较。
回顾
现在您已经可以正确测试 NULL:
IS NULL/IS NOT NULL是唯一正确且可移植的 NULL 测试;它们永远不会返回 UNKNOWN。col = NULL始终返回零行,这是一个经典的面试陷阱。- NULL 安全相等比较会将两个 NULL 视为相等:IS NOT DISTINCT FROM(ANSI/Postgres)、<=>(MySQL)、IS(SQLite)。
- 如果不存在相应运算符,请使用
(a = b) OR (a IS NULL AND b IS NULL)。
下一步:使用 COALESCE、NULLIF 以及 ISNULL 等厂商函数为 NULL 提供默认值。
常见问题解答
「IS NULL、IS NOT NULL 与 NULL 安全相等」课时是免费的吗?
是的 — 「IS NULL、IS NOT NULL 与 NULL 安全相等」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。
「IS NULL、IS NOT NULL 与 NULL 安全相等」这节课中我会学到什么?
正确测试 NULL,并掌握各方言中的 NULL 安全运算符 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Coding Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「IS NULL、IS NOT NULL 与 NULL 安全相等」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Coding Interview Prep 课中编写并运行代码吗?
能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 三值逻辑与 UNKNOWN
- IS NULL、IS NOT NULL 与 NULL 安全相等
- COALESCE、NULLIF 与 ISNULL
- 汇总、连接和 DISTINCT 中的 NULL