(转)MySQL中NULL和空值的区别

MySQL中NULL和空值的区别

http://www.ywnds.com/?p=10295

学习过关系型数据库的伙伴都知道,NULL是指不确定的值,在数据库中绝对是噩梦的存在;而空值,一般对字符串类型而言,指没有任何值的字符串类型,为字符类型的变量设置为空值:set @vs=”,空值跟无值不同。有人可能会问,无值是什么?无值,是指数据表中没有任何数据。无值和不确定值,单从字面意思上来看,两者之间的定义很清楚,一旦深究,这两者之间的关系,有时令人十分迷惑(confused)。

MySQL中的NULL值和空值区别,注意到NULL值是未知的,占用空间,并且不走索引。相信很多用了MySQL很久的人,对这两个字段属性的概念还不是很清楚,一般会有以下疑问:

1、我字段类型是not null,为什么我可以插入空值?

2、为什么not null的效率比null高?

3、判断字段不为空的时候,到底要select * from table where column <> ”还是要用select * from table where column is not null呢?

带着上面几个疑问,我们来深入研究一下null和not null到底有什么不一样。

首先,我们要搞清楚“空值” 和 “NULL” 的概念:

1、空值是不占用空间的。

2、MySQL中的NULL其实是占用空间的,下面是来自于MYSQL官方的解释

“NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”

打个比方来说,你有一个杯子,空值代表杯子是真空的,NULL代表杯子中装满了空气,虽然杯子看起来都是空的,但是区别是很大的。

搞清楚“空值”和“NULL”的概念之后,问题基本就明了了,我们搞个例子测试一下:


CREATE TABLE  `test` (
`col1` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`col2` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL
) ENGINE = INNODB;

CREATE TABLE  `test` (
`col1` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`col2` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL
) ENGINE = INNODB;
插入数据:


mysql> INSERT INTO `test` VALUES (NULL,1);
ERROR 1048 (23000): Column 'col1' cannot be null
1
2
mysql> INSERT INTO `test` VALUES (NULL,1);
ERROR 1048 (23000): Column 'col1' cannot be null
MySQL发生错误,再来一条:


mysql> INSERT INTO `test` VALUES ('NULL',1);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO `test` VALUES ('',1);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO `test` VALUES ('NULL',1);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO `test` VALUES ('',1);
Query OK, 1 row affected (0.01 sec)
成功插入。

可见,NOT NULL的字段是不能插入“NULL”的,只能插入“空值”或有值,上面的问题1也就有答案了。另外,我这里是’NULL’相当于一个字符串了,不是NULL值,比如IS NULL是查不出来的。


mysql> select * from test1 where col1 is null;
Empty set (0.00 sec)
1
2
mysql> select * from test1 where col1 is null;
Empty set (0.00 sec)
而等于’NULL’可以查询:


mysql> select * from test1 where col1='null';
+------+------+
| col1 | col2 |
+------+------+
| NULL | 1    |
+------+------+
1 row in set (0.00 sec)

mysql> select * from test1 where col1='null';
+------+------+
| col1 | col2 |
+------+------+
| NULL | 1    |
+------+------+
1 row in set (0.00 sec)
对于问题2,上面我们已经说过了,NULL其实并不是空值,而是要占用空间,所以MySQL在进行比较的时候,NULL会参与字段比较,所以对效率有一部分影响。

而且对表索引时不会存储NULL值的,所以如果索引的字段可以为NULL,索引的效率会下降很多。

我们再向test的表中插入几条数据:


mysql> INSERT INTO `test` VALUES ('', NULL);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `test` VALUES ('1', '2');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `test` VALUES ('', NULL);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `test` VALUES ('1', '2');
Query OK, 1 row affected (0.00 sec)
现在表中数据:

现在根据需求,我要统计test表中col1不为空的所有数据,我是该用“<> ”” 还是 “IS NOT NULL” 呢,让我们来看一下结果的区别。


mysql> select * from test1 where col1 is null;
Empty set (0.00 sec)

mysql> select * from test1 where col2 is null;
+------+------+
| col1 | col2 |
+------+------+
|      | NULL |
+------+------+
1 row in set (0.00 sec)

mysql> select * from test1 where col1 is null;
Empty set (0.00 sec)

mysql> select * from test1 where col2 is null;
+------+------+
| col1 | col2 |
+------+------+
|      | NULL |
+------+------+
1 row in set (0.00 sec)

mysql> select * from test1 where col1 <> '';
+------+------+
| col1 | col2 |
+------+------+
| NULL | 1    |
| 1    | 2    |
+------+------+
2 rows in set (0.00 sec)

mysql> select * from test1 where col1 <> '';
+------+------+
| col1 | col2 |
+------+------+
| NULL | 1    |
| 1    | 2    |
+------+------+
2 rows in set (0.00 sec)
可以看到,结果迥然不同,所以我们一定要根据业务需求,搞清楚到底是要用那种搜索条件。

------------------------------------------------->

MySQL数据库是一个基于结构化数据的开源数据库,SQL语句是MySQL数据库中核心语言。不过在MySQL数据库中执行SQL语句,需要小心两个陷阱。

陷阱一:空值不一定为空

空值是一个比较特殊的字段。在MySQL数据库中,在不同的情形下,空值往往代表不同的含义。这是MySQL数据库的一种特性。如在普通的字段中(字符型的数据),空值就是表示空值。但是如果将一个空值的数据插入到TimesTamp类型的字段中,空值就不一定为空。此时为出现什么情况呢?

我先创建了一个表。在这个表中有两个字段:User_id(其数据类型是int)、Date(其数据类型是TimesTamp)。现在往这个表中插入一条记录,其中往Date字段中插入的是一个NULL空值。可是当我们查询时,其结果显示的却是插入记录的当前时间。这是怎么一回事呢?其实这就是在MySQL数据库中执行SQL语句时经常会遇到的一个陷阱:空值不一定为空。在操作时,明明插入的是一个空值的数据,但是最后查询得到的却不是一个空值。

在MySQL数据库中,NULL对于一些特殊类型的列来说,其代表了一种特殊的含义,而不仅仅是一个空值。对于这些特殊类型的列,主要是要记住两个。一个就是笔者上面举的TimesTamp数据类型。如果往这个数据类型的列中插入Null值,则其代表的就是系统的当前时间。另外一个是具有auto_increment属性的列。如果往这属性的列中插入Null值的话,则系统会插入一个正整数序列。而如果在其他数据类型中,如字符型数据的列中插入Null的数据,则其插入的就是一个空值。

陷阱二:空值不一定等于空字符

在MySQL中,空值(Null)与空字符(’’)相同吗?答案是否定的。

在同一个数据库表中,同时插入一个Null值的数据和一个’’空字符的数据,然后利用Select语句进行查询。显然其显示的结果是不相同的。从这个结果中就可以看出,空值不等于空字符。这就是在MySQL中执行SQL语句遇到的第二个陷阱。在实际工作中,空值数据与空字符往往表示不同的含义。数据库管理员可以根据实际的需要来进行选择。如对于电话号码等字段,可以默认设置为空值(表示根本不知道对方的电话号码)或者设置为空字符(表示后来取消了这个号码)等等。由于他们在数据库中会有不同的表现形式,所以数据库管理员需要区别对待。笔者更加喜欢使用空值,而不是空字符。这主要是因为针对空值这个数据类型有几个比较特殊的运算字符。如果某个字段是空字符,数据库中是利用字段名称来代替。相反,如果插入的是空值,则直接显示的是NULL。这跟其他数据库的显示方式也是不同的。

IS NULL和IS NOT NULL关键字。如果要判断某个字段是否含用空值的数据,需要使用特殊的关键字。其中前者表示这个字段为空,后者表示这个字段为非空。在Select语句的查询条件中这两个关键字非常的有用。如需要查询所有电话号码为空的用户(需要他们补充电话号码信息),就可以在查询条件中加入is not null关键字。判断NULL用is null或者is not null,SQL语句里可以用ifnull函数来处理。判断空字符串‘’,要用=”或者<>”,SQL语句里可以用if(col,col,0)处理,即:当col为true时(非null,及非”)显示,否则打印0。

一般情况下,除了count(0),count(*)之外,聚合函数都会忽略NULL值,而统计非NULL值。另外空表也会产生结果为NULL的聚合值。当聚合列值都是NULL值时,由于聚合函数忽略NULL值,因此,当计算聚合函数(max,min,avg和sum)的聚合值时,由于无值可以聚合,数据库引擎不能确定这些聚合函数的返回值,因此,数据库引擎返回NULL值。


mysql> create table temp(id int);
Query OK, 0 rows affected (0.06 sec)

mysql> insert into temp values(null);
Query OK, 1 row affected (0.01 sec)

mysql> select count(0),count(id),max(id),min(id),avg(id),sum(id) from temp;
+----------+-----------+---------+---------+---------+---------+
| count(0) | count(id) | max(id) | min(id) | avg(id) | sum(id) |
+----------+-----------+---------+---------+---------+---------+
|        1 |         0 |    NULL |    NULL |    NULL |    NULL |
+----------+-----------+---------+---------+---------+---------+
1 row in set (0.00 sec)

mysql> create table temp(id int);
Query OK, 0 rows affected (0.06 sec)

mysql> insert into temp values(null);
Query OK, 1 row affected (0.01 sec)

mysql> select count(0),count(id),max(id),min(id),avg(id),sum(id) from temp;
+----------+-----------+---------+---------+---------+---------+
| count(0) | count(id) | max(id) | min(id) | avg(id) | sum(id) |
+----------+-----------+---------+---------+---------+---------+
|        1 |         0 |    NULL |    NULL |    NULL |    NULL |
+----------+-----------+---------+---------+---------+---------+
1 row in set (0.00 sec)
聚合函数(max,min,sum,avg和count)忽略null值,但不代表聚合函数不返回null值:如果数据表为空表,或聚合列值都是null,那么max,min,sum,avg聚合函数返回null值,而count 聚合函数返回0。聚合函数的共性:Null values are ignored。

不再迷惑:当不返回任何值时,数据库引擎不确定返回值,就把无值转换为NULL值。

猜你喜欢

转载自jackyrong.iteye.com/blog/2394225