SQL中的NULL表示缺失的、未知的数据值,和普通的有值数据不同,NULL不参与常规的布尔判断,由此衍生出了三值逻辑规则,这是SQL处理NULL值的核心逻辑体系。

什么是SQL的三值逻辑
常规的布尔逻辑只有真(TRUE)和假(FALSE)两种结果,而SQL中引入NULL后,判断结果新增了未知(UNKNOWN)状态,三种结果共同构成了三值逻辑。当判断条件中包含NULL值时,结果不会直接返回真或假,而是返回未知,这个特性会直接影响查询条件、连接操作、聚合计算等多个场景的结果。
三值逻辑的核心判断规则
三值逻辑下的比较运算和逻辑运算都有固定的结果规则,我们逐一来看:
比较运算规则
任何包含NULL的比较运算,结果都是未知,具体规则如下:
- NULL = 任意值:结果为UNKNOWN
- NULL != 任意值:结果为UNKNOWN
- NULL > 任意值:结果为UNKNOWN
- NULL < 任意值:结果为UNKNOWN
- NULL = NULL:结果为UNKNOWN
需要注意的是,SQL中判断NULL值是否相等不能用等号,必须使用IS NULL或者IS NOT NULL运算符,这两个运算符的结果只有真和假,不会出现未知状态。
逻辑运算规则
三值逻辑下的AND、OR、NOT运算规则如下,其中U代表UNKNOWN:
| 运算类型 | 左操作数 | 右操作数 | 结果 |
|---|---|---|---|
| AND | TRUE | U | U |
| FALSE | U | FALSE | |
| U | U | U | |
| OR | TRUE | U | TRUE |
| NOT | U | 无 | U | FALSE | U | U | U | U | U |
三值逻辑的实际场景示例
我们通过具体的SQL示例来理解三值逻辑的实际影响,首先创建一张测试表并插入数据:
-- 创建测试表
CREATE TABLE test_null (
id INT PRIMARY KEY,
score INT
);
-- 插入测试数据,其中id为3的记录score为NULL
INSERT INTO test_null (id, score) VALUES (1, 80);
INSERT INTO test_null (id, score) VALUES (2, 90);
INSERT INTO test_null (id, score) VALUES (3, NULL);
INSERT INTO test_null (id, score) VALUES (4, 70);
WHERE条件筛选场景
当我们执行查询语句筛选score大于75的记录时:
SELECT * FROM test_null WHERE score > 75;
这条语句只会返回id为1和2的记录,id为3的记录score是NULL,score > 75的判断结果是未知,不会被纳入结果集。如果要查询score小于等于75或者为NULL的记录,需要写成:
SELECT * FROM test_null WHERE score <= 75 OR score IS NULL;
聚合函数计算场景
聚合函数计算时会自动忽略NULL值,比如计算score的平均值:
SELECT AVG(score) AS avg_score FROM test_null;
计算时只会取id为1、2、4的三条记录的score值,总和是80+90+70=240,平均值是80,NULL值不会被计入计算范围。
连接查询场景
如果两张表通过可能为NULL的字段进行连接,三值逻辑也会影响连接结果。比如另一张表test_extra的id字段可能为NULL,连接时NULL值不会匹配到任何记录,只有非NULL且相等的id才会产生连接结果。
三值逻辑的常见误区
很多开发者容易陷入以下误区:
- 误以为NULL等于NULL,使用
WHERE score = NULL筛选NULL值,实际上这条语句的结果永远是未知,不会返回任何记录,正确写法是WHERE score IS NULL - 认为NOT (NULL > 10)的结果是假,实际上NULL > 10的结果是未知,NOT未知的结果还是未知,同样不会返回记录
- 在CHECK约束中使用包含NULL的条件,比如
score > 0,那么score为NULL的记录会被允许插入,因为判断结果是未知,CHECK约束只拒绝结果为假的记录
理解SQL的三值逻辑规则,能够帮助我们在编写查询、约束、计算逻辑时准确预判结果,避免出现不符合预期的数据处理问题。