问题
给定表 customer
,里面保存了所有客户信息和他们的推荐人。
+------+------+-----------+
| id | name | referee_id|
+------+------+-----------+
| 1 | Will | NULL |
| 2 | Jane | NULL |
| 3 | Alex | 2 |
| 4 | Bill | NULL |
| 5 | Zack | 1 |
| 6 | Mark | 2 |
+------+------+-----------+
写一个查询语句,返回一个客户列表,列表中客户的推荐人的编号都 不是 2。
结果示例
对于上面的示例数据,结果为:
+------+
| name |
+------+
| Will |
| Jane |
| Bill |
| Zack |
+------+
解答思路
一开始拿到这个题的做法是:
# Write your MySQL query statement below
SELECT name
FROM customer
WHERE referee_id <> 2;
但是结果报错,发现所有referee_id
为NULL
的数据都被忽略了。同样,使用过滤条件 WHERE referee_id <> 2 OR referee_id = NULL
也是错的,为什么?
查了一些解答,总结一下:
首先,来了解一下 MySQL背后的三值逻辑:TRUE
、FALSE
、UNKOWN
。
TRUE
和FALSE
很好理解,真和假。
对于UNKOWN
和NULL
,也有一个非常通俗的解释(来源于文末参考链接中的橡树😎):
UNKOWN
是说,“未知”。当人们戴上墨镜之后,人们不知道墨镜底下的眼珠是什么颜色,这就是未知,即“unknown”。虽然不知道,但是人的眼珠不管是红色、黑色还是棕色,肯定是有颜色的。
放在数据表中同理,我们拿到Jane的推荐人id,发现是NULL
,不是因为推荐人没有id,而是因为我们不知道这个对应的推荐人id是什么而已。
同样,对于NULL
,还有另外一种解释:
inapplicable,不适用。比如一个属性,生理性别,对于人来说,这个属性有意义,每个人都有对应的生理性别属性:男/女。但是对于物品,比如电脑、冰箱来说,是没有这个属性的。因此也被称为“不适用”。
现有的DBMS将两种类型的NULL
归为一类,并采用了上面提到的三值逻辑。
那么查询结果中为什么不会包含含有在这里插入代码片
NULL的行呢?这是因为查询结果中只会包含 WHERE子句中判断结果为TRUE的行,FALSE
和UNKNOWN
不在考虑范围内。因此 我们如果要查推荐人的编号不是2,不应该使用referee_id != 2
(referee_id <> 2
)这样的条件,这会导致UNKOWN的情况被忽略了。
那么可不可以使用 referee_id = NULL
呢?答案也是否定的。
为什么?
划重点!!!因为NULL不是值,类似于汉语的说话习惯,MySQL中也有所谓的谓词,比如(=,>,<>等等用来判断值的保留字),但是由于NULL本身不属于值得一种,因此对其使用谓词,返回得结果必然不可能是TRUE,而是UNKNOWN。
那这道题应该用什么呢?答案是IS NULL
或IS NOT NULL
。首先,IS NULL
不是IS
和NULL
。而仅仅是对某个字符是否为空的一种判断,再想象一下一个例子:在某个表中,一个人的性别不知道,显示为NULL
,我们在描述这个情况时,可以认为数据遗漏,这个人的性别信息是未知的,但是我们不能直接使用一些谓词,比如=,<,>,!=
对性别信息是未知的这一现象进行判断。
小结
当原数据中含有NULL
时,最好用IS NULL
或IS NOT NULL
作为WHERE的补充过滤条件。
正确代码
# Write your MySQL query statement below
SELECT name
FROM customer
WHERE referee_id <> 2 OR referee_id IS NULL;
参考资料:
[1] https://leetcode-cn.com/problems/find-customer-referee/solution/san-by-xiang-shu-k-7ywp/