三值逻辑与 UNKNOWN
了解 NULL = NULL 为什么不为 TRUE,以及 UNKNOWN 如何在条件中传播
三值逻辑与 UNKNOWN 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。
为什么 NULL 会让候选人答错
NULL 是结构化查询语言面试中错误答案的首要来源。陷阱在于把它当作普通值,而实际上 NULL 表示“未知”或“缺失”,既不是零,也不是空字符串。
面试官喜欢考查这一点,因为语法看起来正确,但结果会悄然出错。他们可能会给您一个“应该”返回某行的筛选条件,然后问您为什么它什么也没有返回。
本课将帮助您建立能够化解所有 NULL 问题的思维模型:三值逻辑。一旦您理解比较结果可能是 TRUE、FALSE 或 UNKNOWN,后面的内容就顺理成章了。
NULL 不是值
面试中最重要的一句话是:NULL 表示没有值,而不是值本身。
这意味着您不能像比较数字那样使用 = 来比较它。数据库无法确定两个未知值是否相等,因此不会断言结果是 TRUE 还是 FALSE。
NULL = 5不是 FALSE,而是 UNKNOWNNULL = NULL不是 TRUE,而是 UNKNOWNNULL <> NULL同样是 UNKNOWN
这就是可为空列上的简单等值筛选会悄悄排除行的原因。
二值逻辑与三值逻辑
大多数编程语言使用二值逻辑:表达式要么是 TRUE,要么是 FALSE。只要比较中涉及 NULL,结构化查询语言就会增加第三种结果:UNKNOWN。
因此,结构化查询语言中的任何谓词都可能计算出三种结果之一:TRUE、FALSE 或 UNKNOWN。WHERE 子句只保留其谓词恰好为 TRUE 的行。对于筛选来说,UNKNOWN 的行为类似 FALSE,但从逻辑上看二者并不相同。
面试官会考查您是否了解这一差异,因为 UNKNOWN 在 NOT 下的行为与 FALSE 不同。
会悄悄排除行的筛选条件
下面是一个经典的完整示例。假设 bonus 有时为 NULL。招聘人员问道:“这个查询应该返回奖金不是 1000 的所有人。为什么没有奖金的员工会被跳过?”
对于 bonus 为 NULL 的行,bonus <> 1000 的结果是 UNKNOWN,而不是 TRUE。WHERE 只保留 TRUE 行,因此这些员工就消失了。
解决方法是显式处理 NULL,我们将在下一课中介绍。目前请先认识到,缺失的行是逻辑运算的结果,而不是程序错误。
SELECT name, bonus
FROM employees
WHERE bonus <> 1000;
-- Rows where bonus IS NULL are excluded:
-- NULL <> 1000 evaluates to UNKNOWN, not TRUEAND 表达式中的 NULL
三值逻辑会改变 AND 的行为。记住下面的规则,您就能当场回答任何真值表问题。
- TRUE AND UNKNOWN = UNKNOWN
- FALSE AND UNKNOWN = FALSE
- UNKNOWN AND UNKNOWN = UNKNOWN
直观地说,AND 只需要一个 FALSE 就能确定结果为 FALSE。因此,FALSE AND 任何值都仍然是 FALSE。但 TRUE AND 未知值仍然是未知,因为未知的一侧最终可能变成任意结果。
-- If status = 'active' is TRUE but bonus = 100 is UNKNOWN:
SELECT *
FROM employees
WHERE status = 'active' AND bonus = 100;
-- Combined result is UNKNOWN, so the row is NOT returnedOR 表达式中的 NULL
OR 的规则与 AND 相对应。它只需要一个 TRUE 就能确定结果为 TRUE,因此 TRUE 会跳过未知结果的影响。
- TRUE OR UNKNOWN = TRUE
- FALSE OR UNKNOWN = UNKNOWN
- UNKNOWN OR UNKNOWN = UNKNOWN
所以,即使某个分支的结果未知,只要另一个分支确实为 TRUE,该行仍然可以匹配 OR 条件。这是继 AND 问题之后经常出现的追问。
SELECT *
FROM employees
WHERE department = 'Sales' OR bonus = 100;
-- A Sales employee with NULL bonus:
-- TRUE OR UNKNOWN = TRUE, so the row IS returnedNOT 会翻转 TRUE/FALSE,但不会翻转 UNKNOWN
这是面试官通常留到最后考查的细节。NOT 会将 TRUE 反转为 FALSE,将 FALSE 反转为 TRUE,但NOT UNKNOWN 仍然是 UNKNOWN。
这就是为什么您不能只是用 NOT 包裹一个失败的条件来翻转结果。如果对于 NULL 行,bonus = 1000 的结果是 UNKNOWN,那么 NOT (bonus = 1000) 的结果也仍然是 UNKNOWN,该行依然会被排除。
否定操作无法挽回 NULL 行,只有显式的 IS NULL 检查才能做到这一点。
-- For a row where bonus IS NULL:
-- bonus = 1000 -> UNKNOWN
-- NOT (bonus = 1000) -> UNKNOWN (still excluded)
SELECT * FROM employees WHERE NOT (bonus = 1000);完整示例:NOT IN 陷阱
这是最常被问到的 NULL 谜题之一。当 NOT IN 的列表包含 NULL 时,它会完全不返回任何行,这会让原本以为它只会跳过 NULL 的候选人感到意外。
在底层,x NOT IN (1, 2, NULL) 会展开为 x <> 1 AND x <> 2 AND x <> NULL。最后一个比较结果是 UNKNOWN,而 TRUE AND TRUE AND UNKNOWN 会归结为 UNKNOWN,因此没有任何内容符合条件。
安全的替代方案是 NOT EXISTS,它不会受到这个问题的影响。
-- Returns ZERO rows if the subquery yields any NULL
SELECT name
FROM employees
WHERE manager_id NOT IN (SELECT manager_id FROM managers);
-- Each comparison against NULL becomes UNKNOWN,
-- and the AND-chain collapses to UNKNOWN for every row.为什么 UNKNOWN 在 WHERE 中的行为像 FALSE
一个常见的追问是:“如果 UNKNOWN 不是 FALSE,为什么该行会像 FALSE 行一样被排除?”
答案很明确:WHERE、ON 和 HAVING 都采用仅保留 TRUE的规则。FALSE 和 UNKNOWN 都无法通过这一检查,因此在筛选过程中看起来相同。
只有在否定操作和 CHECK 约束中,二者的差异才会显现。CHECK 约束在条件为 TRUE或 UNKNOWN 时会允许行通过,因此 NULL 可能绕过您以为能够阻止它的 CHECK。
-- CHECK passes on TRUE or UNKNOWN, so NULL salary is allowed:
-- CONSTRAINT salary_positive CHECK (salary > 0)
-- INSERT ... salary = NULL -> NULL > 0 is UNKNOWN -> allowed深入示例:COUNT 与真值判断的差距
用一个真实的面试题把这些内容串起来:“我们有 100 名员工。SELECT COUNT(*) WHERE bonus = 100 返回 30,而 WHERE bonus <> 100 返回 50。其他 20 名员工去哪儿了?”
缺失的 20 名员工的奖金是 NULL。对于他们,= 100 和 <> 100 都不为 TRUE,而是 UNKNOWN,因此他们完全无法通过这两个筛选条件。
回答“各组数量之和不等于总数,是因为 NULL 不满足任何一个谓词”,正是面试官想听到的答案。
SELECT
COUNT(*) FILTER (WHERE bonus = 100) AS eq_100,
COUNT(*) FILTER (WHERE bonus <> 100) AS ne_100,
COUNT(*) FILTER (WHERE bonus IS NULL) AS null_bonus,
COUNT(*) AS total
FROM employees;面试要点
当谈到 NULL 逻辑时,请说明以下几点,以体现您的资深水平:
- NULL 表示未知;与它进行比较会得到 UNKNOWN。
- 结构化查询语言使用三值逻辑:TRUE、FALSE、UNKNOWN。
- WHERE、ON 和 HAVING只保留 TRUE行。
NOT UNKNOWN仍然是 UNKNOWN,因此否定操作不会找回 NULL 行。- 包含任何 NULL 的
NOT IN都不会返回任何行;请优先使用NOT EXISTS。
请先说明模型,再演示真值表。这种顺序表明您理解的是原理,而不只是记住了技巧。
快速检查
检验您对三值逻辑的掌握程度。
回顾
现在您已经掌握了 NULL 的核心思维模型:
- NULL 表示未知,不是值;永远不要使用
=或<>比较它。 - 结构化查询语言采用三值逻辑:谓词返回 TRUE、FALSE 或 UNKNOWN。
- 筛选子句只保留 TRUE;UNKNOWN 行会像 FALSE 行一样消失。
NOT会翻转 TRUE 和 FALSE,但不会改变 UNKNOWN。NOT IN与 NULL 结合会触发陷阱并返回零行;请使用NOT EXISTS。
下一课将介绍使用 IS NULL、IS NOT NULL 和 NULL 安全等值运算符检查 NULL 的正确方法。
常见问题解答
「三值逻辑与 UNKNOWN」课时是免费的吗?
是的 — 「三值逻辑与 UNKNOWN」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。
「三值逻辑与 UNKNOWN」这节课中我会学到什么?
了解 NULL = NULL 为什么不为 TRUE,以及 UNKNOWN 如何在条件中传播 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Coding Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「三值逻辑与 UNKNOWN」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Coding Interview Prep 课中编写并运行代码吗?
能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。