数据库系统工程师 · 高频练习

NOT IN 子查询结果含 NULL 时,为什么可能一行也查不出来?

中级 单选题 第 904 题 中等 数据库系统工程师SQLNOT INNULL三值逻辑
题目

表 orders 的 customer_id 均为非空。执行查询:`SELECT * FROM orders WHERE customer_id NOT IN (SELECT customer_id FROM blacklist);`。若子查询结果中包含一个 NULL,最可能出现的情况是()。

A NULL 会被自动忽略,结果与子查询不含 NULL 完全相同
B 只返回 customer_id 为 NULL 的订单
C 比较结果受 UNKNOWN 影响,可能没有任何订单满足 WHERE 条件
D 数据库会把 NULL 当作 0 参与比较
题目类型:原创高频练习题 用途:用于帮助理解数据库系统工程师相关考点和答案解析,不等同于官方真题。
正确答案
C
答案解析

SQL 中与 NULL 的普通比较结果不是 TRUE 或 FALSE,而是 UNKNOWN。`x NOT IN (1, NULL)` 等价于 `x<>1 AND x<>NULL`,其中 `x<>NULL` 为 UNKNOWN;WHERE 只保留 TRUE,因此即使 x 不等于 1,也可能不会返回。

选项分析

A

错误。普通比较不会自动忽略 NULL,除非查询显式过滤或数据库进行了语义等价的安全优化。

B

错误。题干已说明 orders.customer_id 非空,而且 NOT IN 也不是专门筛选空值的语法。

C

正确。子查询中的 NULL 会把否定比较带入 UNKNOWN,WHERE 不会保留 UNKNOWN。

D

错误。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。