MySQL之薛定谔的NULL

147 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

薛定谔的NULL

表数据如下所示:
+----------+------+
| name     | age  |
+----------+------+
| xiaoming |   13 |
| xiaohong |   13 |
| xiaogang |   14 |
| xiaofa   |   14 |
| xiaoliu  | NULL |
+----------+------+

我们想完成以下两个查询:

1. 查询age属于(13NULL)的记录
mysql> SELECT * FROM STUDENTS WHERE AGE IN (13,NULL);
+----------+------+
| name     | age  |
+----------+------+
| xiaoming |   13 |
| xiaohong |   13 |
+----------+------+
2 rows in set (0.00 sec)

2. 查询age不属于(13NULL)的记录
mysql> SELECT * FROM STUDENTS WHERE AGE NOT IN (13,NULL);
Empty set (0.00 sec)

结果并非我们预期的一样:

  1. 查询1缺少了xiaoliu NULL这条记录
  2. 查询2缺少了 xiaogang14, xiaofa 14 两条记录

原因在于MySQL中,任何数据都等于NULL,任何数据都不等于NULL,即

x == NULL // false
x != NULL // false
x为任意数据,包括NULL

一般来说,两个数的关系只可能是相等和不相等二者之一,然而MySQL中的NULL却做到了时而相等时而不相等。。。

根据上述分析,修改查询如下:

mysql> SELECT * FROM STUDENTS WHERE AGE IN (13) OR AGE IS NULL;
+----------+------+
| name     | age  |
+----------+------+
| xiaoming |   13 |
| xiaohong |   13 |
| xiaoliu  | NULL |
+----------+------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM STUDENTS WHERE AGE NOT IN (13);
+----------+------+
| name     | age  |
+----------+------+
| xiaogang |   14 |
| xiaofa   |   14 |
+----------+------+
2 rows in set (0.00 sec)

总结,使用=, !=, <>与NULL比较的结果都是false,正确的比较方式是使用is null,is not nuill

关于NULL的知识点

  1. 允许为NULL的字段是可以使用索引的,如普通索引、复合索引、全文索引等不会使索引失效。只有在使用空间索引时, 索引列必须为NOT NULL。
  2. count(columnName)不会统计值为NULL的行。
  3. 在允许为NULL的字段建立索引时,key_len会比有NOT NULL约束时多一个字节,原因在于需要用一个字节来标记是否为NULL。