请使用支持现代 CSS 与 JavaScript 的浏览器播放课件
DBPA · 3.5

空值的处理

为什么没有值会改变查询结果

VER. 2608.2 Built with impress.js

学习目标

NULL 的业务语义会影响约束判断、运算结果和查询筛选

  1. 01区分 NULL 与 0、空串和文字 'NULL',并解释未知、不适用和不便提供三类语境
  2. 02追踪 NULL 由插入、更新和外连接产生的路径
  3. 03用 IS NULL 与 IS NOT NULL 正确筛选空值
  4. 04解释 NOT NULL、主码和 UNIQUE 的约束边界
  5. 05用 UNKNOWN 解释比较和逻辑运算
  6. 06判断 WHERE 与 HAVING 会保留哪些结果
2/15
LEARNING OBJECTIVES

NULL 不是 0、空串或一段文字

NULL 表示当前没有确定且可用的值;具体原因可能是未知、不适用或不便提供

语境含义例子
未知应该有值但目前不知道漏填出生日期
不适用当前对象或状态不需要这个值缺考没有成绩
不便提供值可能存在,但当前不宜填写不愿公开的联系方式

0 是已知数值零;'' 是已知的空字符串;'NULL' 是四个字符的文字;NULL 不是它们中的任何一个

Takeaway

显示或统计 NULL 前,必须先确定它的业务语义

3/15
NULL MEANING

NULL 可以从三条数据路径产生

插入、更新和外连接产生 NULL 的位置与业务语义不同

插入

省略可空列或显式写入 NULL;SC.Grade 未列出 → NULL

更新

UPDATE ... SET Smajor = NULL,元组仍存在而属性被置空

外连接

未匹配时另一侧列只在查询结果中补为 NULL,不写回基本表

Takeaway

空值不是删除记录的替代方式

4/15
NULL SOURCES

INSERT 省略列:DEFAULT 与 NULL

省略 INSERT 列表中的列不会删除表列,而是让该元组在该列取 NULL 或默认值

SQL
INSERT INTO SC(Sno, Cno, Semester)
VALUES ('20180006', '81004', '20211');

-- Grade、Teachingclass 未列出,因此取 NULL
-- 显式写 NULL 也会得到相同结果
Takeaway

显式写 NULL 或省略可空且无 DEFAULT 的列会产生 NULL;NOT NULL 且无 DEFAULT 的列不能省略,有 DEFAULT 时取默认值

5/15
NULL INSERT

判断空值必须使用 IS NULL

等号比较不能把 NULL 当成普通常量

SQL
SELECT Sno, Cno
FROM SC
WHERE Grade IS NULL;
写法作用结论
Grade IS NULL找到缺少成绩的记录正确判断
Grade IS NOT NULL找到已有成绩的记录正确判断
Grade = NULL把空值当普通值比较得到 UNKNOWN,不是 TRUE
6/15
NULL PREDICATES

约束决定一列能不能取空值

主码、非空和唯一约束的边界不同

约束空值边界课堂判断
NOT NULL禁止该列为空必须提供值或默认值
主码(Student.Sno不能为空且必须唯一不能用 NULL 标识主体
复合主码(SC.(Sno, Cno)组合唯一且两个组成列都不能为 NULLSnoCno 单列可以重复
UNIQUE(扩展示例)标准约束;多个 NULL 的处理由 DBMS 定义当前 Student/SC 基础 DDL 未定义;MySQL 8.4 的可空 UNIQUE 可允许多个 NULL
可空外码(Course.CpnoNULL 不要求匹配父表;非 NULL 必须有效空外码不等于无效外码
Takeaway

UNIQUE 本身是标准约束;可空 UNIQUE 的多个 NULL 只是产品边界,不是当前 Student/SC 已有的约束

7/15
NULL CONSTRAINTS

NULL 参与比较会产生 UNKNOWN

含 NULL 的值无法与另一个值确定大小或相等关系

算术

含 NULL 的算术表达式结果通常仍然是 NULL

比较

含 NULL 的比较结果是 UNKNOWN,而不是 FALSE

查询筛选

WHERE 和 HAVING 只保留结果为 TRUE 的行或组

8/15
UNKNOWN

三值逻辑:由典型规则推导 UNKNOWN

下表列出涉及 UNKNOWN 的典型组合;交换 x、y 可得到对称组合,完整真值表还包含其他组合

TRUE、FALSE 与 UNKNOWN 经过 WHERE 筛选,只有 TRUE 被保留
xyx AND yx OR y
TRUEUNKNOWNUNKNOWNTRUE
FALSEUNKNOWNFALSEUNKNOWN
UNKNOWNUNKNOWNUNKNOWNUNKNOWN
Takeaway

FALSE AND UNKNOWN = FALSE | TRUE OR UNKNOWN = TRUE | NOT UNKNOWN 仍然是 UNKNOWN

9/15
THREE VALUED LOGIC

WHERE 只保留条件为 TRUE 的元组

缺考记录不会被 < 60 自动当作不及格

SQL
-- 只找确实不及格的学生
SELECT Sno
FROM SC
WHERE Grade < 60
  AND Cno = '81001';

-- 如果业务也要包含缺考
SELECT Sno
FROM SC
WHERE Cno = '81001'
  AND (Grade < 60 OR Grade IS NULL);
Takeaway

第一条只返回确实不及格的学生;第二条把缺考记录显式纳入。WHERE 与 HAVING 都只保留 TRUE,第二条用 OR 把 NULL 记录纳入结果

10/15
QUERY FILTER

聚集函数对空值的处理也有差异

统计元组与统计非空列值不是同一个问题

写法统计对象空值影响
COUNT(*)元组数量不因某列为空而减少
COUNT(Grade)非空成绩数量跳过 Grade 为 NULL 的行
AVG(Grade)非空成绩平均值不把缺考当成零分
Takeaway

若成绩为 80、NULL、60COUNT(*) = 3COUNT(Grade) = 2AVG(Grade) = 70。若一组 Grade 全为 NULL:COUNT(Grade) = 0AVG(Grade) = NULLHAVING AVG(Grade) >= 60 得到 UNKNOWN,不保留该组

11/15
NULL AND AGGREGATION

处理 NULL 时要依次检查语义、约束和结果

只记住谓词或真值表的一格,不能说明实际查询结果

先问含义

先确定 NULL 表示未知、不适用还是不便提供

再看约束

再检查列是否允许为空,以及它是否是主码或外码

最后查结果

最后确认查询是否要显式纳入 NULL,或更新是否应写入 NULL 而不是 0、空串或默认值

12/15
NULL REASONING

用语义、约束和三值逻辑判断 NULL

NULL 不只是显示为空,它还会改变约束判断、运算结果和查询筛选

产生

INSERT、UPDATE 和外连接都可能生成 NULL,但生成位置和业务含义不同

判断

判断 NULL 时使用 IS NULL 与 IS NOT NULL,而不是普通等号比较

约束

NOT NULL、主码、UNIQUE 与可空外码对 NULL 的约束边界不同

运算与筛选

比较和 AND/OR/NOT 可能得到 UNKNOWN;WHERE、HAVING 只保留 TRUE,聚集函数通常跳过 NULL

Takeaway

缺失值的业务含义必须和 SQL 运算规则同时说明;UPDATE 设为 NULL、设为 0、删除元组是三种不同的数据语义

13/15
RECAP

本节知识地图

14/15
KNOWLEDGE MAP

本节问题

  1. 01NULL 与 0、空串或文字 NULL 有何不同?为什么 Grade = NULL 查不到缺考记录?
  2. 02外连接为什么会产生补位空值,而不是把 NULL 写回基本表?
  3. 03FALSE AND UNKNOWN、TRUE OR UNKNOWN、NOT UNKNOWN 分别是什么结果?
  4. 04如果某学生的 Grade 全为 NULL,COUNT(Grade)、AVG(Grade) 和 HAVING AVG(Grade) >= 60 分别会怎样?
  5. 05当前 Student/SC 基础 DDL 没有 UNIQUE;另设可空 UNIQUE 时,为什么不能把 MySQL 8.4 的多个 NULL 行为推广到其他 DBMS?
15/15
CHECK YOUR UNDERSTANDING