Oracle中NULL比较时值判断与NOT判断均为假的问题咨询
Oracle中NULL值判断取反后无匹配结果的原因
问题复现
测试过程分三步执行SQL:
- 基础CTE查询
WITH a as ( select 1 b, null c from dual) select * from a
- 执行结果:返回1行数据,符合预期。
- 带NULL字段等值过滤的查询
WITH a as ( select 1 b, null c from dual) select * from a where c=1
- 执行结果:无数据返回,符合预期,字段c为NULL,无法满足等于1的判断条件。
- 带NOT取反过滤条件的查询
WITH a as ( select 1 b, null c from dual) select * from a where not(c=1)
- 执行结果:无数据返回,不符合二值逻辑下的预期:按照常规真假判断,
c=1为假则NOT(c=1)应为真,理应返回对应行,但实际无结果。
根本原因
所有遵循SQL标准的数据库(包括Oracle)都采用三值逻辑做条件判断,而非日常认知里的非真即假二值逻辑,逻辑判断的可能结果有三个:TRUE、FALSE、UNKNOWN。
核心规则如下:
- 任何和NULL做普通比较(=、!=、>、<等)的表达式,返回结果既不是真也不是假,而是
UNKNOWN。上述测试里c为NULL,所以c=1的结果是UNKNOWN,不是FALSE。 - WHERE子句仅保留判断结果为
TRUE的行,结果为FALSE和UNKNOWN的行都会被过滤。 - 三值逻辑下NOT运算对
UNKNOWN无效:NOT UNKNOWN的结果仍然是UNKNOWN,不会转为TRUE。
三值逻辑NOT运算对照表
NOT TRUE=FALSENOT FALSE=TRUENOT UNKNOWN=UNKNOWN
所以两次过滤都无返回,本质不是两个条件都判定为假,而是两个条件的结果都是UNKNOWN,都达不到WHERE子句要求的TRUE判定标准。
如果需要正确判断NULL值,不能使用普通比较运算符,必须用专门的IS NULL/IS NOT NULL运算符,这两个运算符对NULL的判断只会返回TRUE或FALSE,不会产生UNKNOWN结果。比如要实现"c不等于1就返回(含c为NULL的场景)"的逻辑,正确写法为:
WITH a as ( select 1 b, null c from dual) select * from a where c != 1 OR c IS NULL
内容的提问来源于stack exchange,提问作者Pierre-olivier Gendraud
相关产品推荐
相关产品推荐

