Kodewick
第 5 课,共 21 课目录

NULL:没有值

第 5 课,共 21 课 · 第 1 部分 · 查数据 · 约 15 分钟

第 1 课里已经见过:有的客户没留邮箱,那一格显示 NULL。

main.sql
1SELECT id, name, email2FROM customers;
输出
idnameemail
1林晓[email protected]
2王磊[email protected]
3陈静NULL
4张伟[email protected]
5刘洋[email protected]
6赵敏NULL
7孙强[email protected]
8周婷[email protected]
9吴昊NULL
10郑雪[email protected]
10 行

NULL 的意思是「没有值」或者「不知道」。它不是 0,也不是空的文字 '':0 是一个数,'' 是一段长度为 0 的文字,而 NULL 什么都不是。这一课讲怎么和它打交道。

找出 NULL:IS NULL

找没留邮箱的客户,要写 IS NULL:

main.sql
1SELECT name, email2FROM customers3WHERE email IS NULL;
输出
nameemail
陈静NULL
赵敏NULL
吴昊NULL
3 行

反过来,IS NOT NULL 找有值的。员工表里,有上级的员工:

main.sql
1SELECT name, manager_id2FROM employees3WHERE manager_id IS NOT NULL;
输出
namemanager_id
马超1
杨帆1
黄磊2
何琳2
高远3
5 行

1 号经理没有上级,他的 manager_id 是 NULL,所以不在结果里。

= NULL 什么也查不到

这是初学者最常踩的坑。

先猜一猜

结果有几行?

1SELECT name2FROM customers3WHERE email = NULL;

运行一下看看:

main.sql
1SELECT name2FROM customers3WHERE email = NULL;
输出
name
空结果(0 行)

为什么?拿一个值和「不知道」比,结果也是「不知道」,不是「成立」。WHERE 只留下条件成立的行,「不知道」的行都被去掉了。就连 NULL = NULL 也是「不知道」:两个不知道的东西,没法说它们相等。

不等于也跳过 NULL

同样的道理,<> 也不会挑出 NULL 的行。邮箱不是 [email protected] 的客户,有几个?

main.sql
1SELECT name, email2FROM customers3WHERE email <> '[email protected]';

10 个客户,去掉林晓,只剩 6 行,不是 9 行:3 个没邮箱的客户也不见了。和 NULL 比较不成立,不等于也不成立。要把它们也算进来,得明说:

main.sql
1SELECT name, email2FROM customers3WHERE email <> '[email protected]' OR email IS NULL;
输出
nameemail
王磊[email protected]
陈静NULL
张伟[email protected]
刘洋[email protected]
赵敏NULL
孙强[email protected]
周婷[email protected]
吴昊NULL
郑雪[email protected]
9 行

NULL 参与计算

SELECT 也可以不写 FROM,直接算几个值。NULL 参与计算,结果还是 NULL;参与比较,结果也是 NULL(「不知道」):

main.sql
1SELECT 10 + NULL, NULL * 2, NULL = NULL, NULL IS NULL;
输出
10 + NULLNULL * 2NULL = NULLNULL IS NULL
NULLNULLNULL1
1 行

只有 IS NULL 给出了确定的答案:1 表示成立(MySQL 用 1 表示成立,0 表示不成立)。

换成别的值:COALESCE

显示结果时,NULL 常常要换成一个看得懂的值。COALESCE(a, b):a 不是 NULL 就用 a,是 NULL 就用 b:

main.sql
1SELECT name, COALESCE(email, '没留邮箱') AS email2FROM customers;
输出
nameemail
林晓[email protected]
王磊[email protected]
陈静没留邮箱
张伟[email protected]
刘洋[email protected]
赵敏没留邮箱
孙强[email protected]
周婷[email protected]
吴昊没留邮箱
郑雪[email protected]
10 行

AS email 给这一列起个名字,不然列名就是一长串 COALESCE(email, '没留邮箱')。下一课细讲 AS。

COALESCE 可以写好几个值,用第一个不是 NULL 的。MySQL 还有一个只接两个值的 IFNULL(a, b);COALESCE 是标准写法,哪个数据库都能用。

NULL 排在哪

按有 NULL 的列排序,MySQL 把 NULL 当成最小的:升序排在最前,降序排在最后:

main.sql
1SELECT name, email2FROM customers3ORDER BY email, id;
输出
10 行

3 个 NULL 的邮箱一样,所以再按 id 排,顺序才定得下来。别的数据库可能相反(PostgreSQL 和 Oracle 把 NULL 排在升序的最后)。

练一练

写好查询,点检查。提示随便看,实在想不出来再看答案。

练习 1

修好它:和 NULL 比较

想查出有上级的员工,显示 name 和 manager_id,按 id 排,可是一行也查不到。改好它。

要显示
namemanager_id
马超1
杨帆1
黄磊2
何琳2
高远3
5 行
exercise1.sql
1SELECT name, manager_id2FROM employees3WHERE manager_id <> NULL4ORDER BY id;
输出
点「运行」或按 Ctrl+Enter
练习 2

联系方式

查出上海的客户,显示 name 和 contact 两列:contact 是邮箱,没有邮箱的显示 无,按 id 排。

要显示
namecontact
林晓[email protected]
陈静无
周婷[email protected]
3 行
exercise2.sql
1SELECT name, email2FROM customers3WHERE city = '上海';
输出
点「运行」或按 Ctrl+Enter
练习 3

一个都不能少

查出邮箱不是 [email protected] 的客户的 name,没有邮箱的客户也要算上,按 id 排。

要显示
name
林晓
陈静
张伟
刘洋
赵敏
孙强
周婷
吴昊
郑雪
9 行
exercise3.sql
1SELECT name2FROM customers3WHERE email <> '[email protected]';
输出
点「运行」或按 Ctrl+Enter

这一课学会了

  • NULL 是「没有值」,不是 0,也不是空的文字。
  • 找它用 IS NULL、IS NOT NULL;= NULL 和 <> NULL 一行也查不到,也不报错。
  • 和 NULL 比较、计算,结果还是 NULL;WHERE 只留下条件成立的行,所以 <> 也会漏掉 NULL 的行。
  • COALESCE(a, b) 把 NULL 换成别的值;MySQL 的 IFNULL 也行,但 COALESCE 哪儿都能用。
  • MySQL 排序时 NULL 最小,别的数据库可能排在最后。