表 orders 的 customer_id 均为非空。执行查询:`SELECT * FROM orders WHERE customer_id NOT IN (SELECT customer_id FROM blacklist);`。若子查询结果中包含一个 NULL,最可能出现的情况是()。
SQL 中与 NULL 的普通比较结果不是 TRUE 或 FALSE,而是 UNKNOWN。`x NOT IN (1, NULL)` 等价于 `x<>1 AND x<>NULL`,其中 `x<>NULL` 为 UNKNOWN;WHERE 只保留 TRUE,因此即使 x 不等于 1,也可能不会返回。
选项分析
错误。普通比较不会自动忽略 NULL,除非查询显式过滤或数据库进行了语义等价的安全优化。
错误。题干已说明 orders.customer_id 非空,而且 NOT IN 也不是专门筛选空值的语法。
正确。子查询中的 NULL 会把否定比较带入 UNKNOWN,WHERE 不会保留 UNKNOWN。
错误。NULL 表示未知或缺失,不会按数字 0 处理。
本题为什么容易错
很多人把 NULL 想成空字符串或 0,于是按普通集合差来理解 NOT IN。SQL 的 NULL 参与等值和不等值比较时都需要走 UNKNOWN,这正是本题的陷阱。
简短答案
NOT IN 子查询结果含 NULL 时,为什么可能一行也查不出来,正确答案是 C(比较结果受 UNKNOWN 影响,可能没有任何订单满足 WHERE 条件)。SQL 中与 NULL 的普通比较结果不是 TRUE 或 FALSE,而是 UNKNOWN。`x NOT IN (1, NULL)` 等价于 `x<>1 AND x<>NULL`,其中 `x<>NULL` 为 UNKNOWN;WHERE 只保留 TRUE,因此即使 x 不等于 1,也可能不会返回。
易混淆概念对比表
| 概念 | 本题判断 | 区别要点 | 记忆提示 |
|---|---|---|---|
| NULL 会被自动忽略,结果与子查询不含 NULL 完全相同 | 本题干扰项 | 错误。普通比较不会自动忽略 NULL,除非查询显式过滤或数据库进行了语义等价的安全优化。 | 看到该词不要急着选,先判断是否真正解决题干问题 |
| 只返回 customer_id 为 NULL 的订单 | 本题干扰项 | 错误。题干已说明 orders.customer_id 非空,而且 NOT IN 也不是专门筛选空值的语法。 | 看到该词不要急着选,先判断是否真正解决题干问题 |
| 比较结果受 UNKNOWN 影响,可能没有任何订单满足 WHERE 条件 | 本题正确答案 | 正确。子查询中的 NULL 会把否定比较带入 UNKNOWN,WHERE 不会保留 UNKNOWN。 | 看到题干核心场景时优先联想到它 |
| 数据库会把 NULL 当作 0 参与比较 | 本题干扰项 | 错误。NULL 表示未知或缺失,不会按数字 0 处理。 | 看到该词不要急着选,先判断是否真正解决题干问题 |
本题易混淆选项怎么区分
- NULL 会被自动忽略,结果与子查询不含 NULL 完全相同:错误。普通比较不会自动忽略 NULL,除非查询显式过滤或数据库进行了语义等价的安全优化。
- 只返回 customer_id 为 NULL 的订单:错误。题干已说明 orders.customer_id 非空,而且 NOT IN 也不是专门筛选空值的语法。
- 数据库会把 NULL 当作 0 参与比较:错误。NULL 表示未知或缺失,不会按数字 0 处理。
知识点详解
SQL WHERE 只保留判断结果为 TRUE 的行,FALSE 和 UNKNOWN 都会被过滤。NOT EXISTS 判断的是相关子查询是否存在匹配行,不需要把候选值与 NULL 逐个做不等比较,因此常用于表达反连接。不过是否改写仍要结合关联列、重复值和业务语义验证。
备考速记
NOT IN 最怕集合里藏着 NULL;未知不算真,所以 WHERE 不放行。
SQL 在三值逻辑场景中的作用
SQL在本题中的核心价值,是解决“表 orders 的 customer_id 均为非空。执行查询:`SELECT * FROM orders WHERE customer_id NOT IN (SELECT customer_id FROM blacklist);`。若子查询结果中包含一个 NULL,最可能出现的情况是()”这个场景问题。复习时不要只背选项名称,还要理解它为什么适用于该场景,以及它能解决哪类安全、流程或管理问题。
同类题怎么考
- 判断 NULL 参与比较后的 TRUE、FALSE、UNKNOWN。
- 比较 NOT IN、NOT EXISTS 在可空字段上的行为差异。
SQL 在数据库系统工程师软考中的考法
软考选择题通常不会只考概念定义,还会把SQL放到三值逻辑场景中,要求判断它的作用、适用范围或与相近概念的区别。遇到这类题时,先抓住题干中的业务场景,再看哪个选项最能解决该场景下的核心问题。
解题思路
这不是数据库闹脾气,而是三值逻辑在起作用。假设黑名单返回 10 和 NULL,订单客户 20 要验证“20 不等于所有黑名单值”。20<>10 为真,但 20<>NULL 无法判断,只能得到 UNKNOWN;真 AND 未知仍是未知,进不了 WHERE。老师在代码评审里看到 NOT IN,通常第一句就会问:子查询列能保证非空吗?
考点定位
看到 NOT IN 与可空子查询列组合,要立即检查 NULL。稳妥处理是子查询先排除 NULL,或按业务语义改写为相关 NOT EXISTS。
易错提醒
- 只看外层列非空,却没有检查子查询返回列是否可空。
- 使用 `= NULL` 或 `<> NULL`,而不是 `IS NULL` 或 `IS NOT NULL`。
- 机械把所有 NOT IN 改成 NOT EXISTS,却没有核对关联条件。
备考提示
- 写 NOT IN 前先确认子查询列有 NOT NULL 约束,或者显式增加 `WHERE customer_id IS NOT NULL`。
- 用一组包含 NULL 的最小测试数据验证查询,比只看正常数据更可靠。
你可能还想了解
- NOT IN 子查询为什么要过滤 NULL?
- NOT EXISTS 一定比 NOT IN 快吗?
- SQL 中 UNKNOWN 在 WHERE 里怎么处理?
本文小结
子查询含NULL时,`x NOT IN (...)`会包含`x<>NULL`这一UNKNOWN判断,整个条件可能无法成为TRUE,所以结果可能为空。应先排除NULL,或按正确关联条件使用NOT EXISTS。