在講null之前一铅,我們先看一個(gè)例子
表數(shù)據(jù)如下:
3306>select * from t1;
+------+-------+
| id | name |
+------+-------+
| 1 | chen |
| 2 | zhang |
| 3 | NULL |
+------+-------+
3 rows in set (0.00 sec)
然后我們想查出所有名字不為'chen'的其它行記錄庄敛,我們有可能這樣寫:
3306>select * from t1 where name!='chen';
+------+-------+
| id | name |
+------+-------+
| 2 | zhang |
+------+-------+
1 row in set (0.00 sec)
但是結(jié)果好像不太如我們所愿,id為1的那條記錄沒有被查出來黔宛,null肯定和'chen'不相等呀鱼填,為什么會(huì)查不出呢?
NUll值對(duì)于新手來說非常容易混淆联逻,經(jīng)常會(huì)被認(rèn)為null與空字符串''是一樣的搓扯,但事實(shí)上,這兩者是非常不一樣遣妥,NULL表示的是“a missing unknown value”擅编,而字符串''是一個(gè)確定的值,這本質(zhì)上就已經(jīng)不一樣了箫踩。
舉個(gè)例子:
mysql> INSERT INTO t_user (phone) VALUES (NULL);
mysql> INSERT INTO t_user (phone) VALUES ('');
第一條insert語句認(rèn)為這個(gè)手機(jī)號(hào)還不確定是多少爱态,是a missing unknown phone number
第二條代表這個(gè)手機(jī)號(hào)碼是確定的,它的手機(jī)號(hào)碼為空字符串
為了處理和null相關(guān)的比較境钟,在mysql中可以用is null锦担、is not null、<=>慨削、isnull()來測(cè)試比較洞渔,不能用如=、<缚态、<>來和null值比較測(cè)試磁椒,任何值(包括和null本身)與null對(duì)比和函數(shù)運(yùn)算操作結(jié)果都為null
如下三個(gè)例子可以說明問題:
任何與null的相關(guān)操作都為null
3306>SELECT NULL, 1+NULL, CONCAT('Invisible',NULL);
+------+--------+--------------------------+
| NULL | 1+NULL | CONCAT('Invisible',NULL) |
+------+--------+--------------------------+
| NULL | NULL | NULL |
+------+--------+--------------------------+
1 row in set (0.00 sec)
3306>SELECT 1>NULL, 1=NULL, 1!=NULL;
+--------+--------+---------+
| 1>NULL | 1=NULL | 1!=NULL |
+--------+--------+---------+
| NULL | NULL | NULL |
+--------+--------+---------+
1 row in set (0.00 sec)
用指定的函數(shù)操作才能返回0或1
3306 > SELECT 1 IS NULL, 1 IS NOT NULL, 1<=>NULL,NULL<=>NULL;
+-----------+---------------+----------+-------------+
| 1 IS NULL | 1 IS NOT NULL | 1<=>NULL | NULL<=>NULL |
+-----------+---------------+----------+-------------+
| 0 | 1 | 0 | 1 |
+-----------+---------------+----------+-------------+
1 row in set (0.00 sec)
但是呢,凡事都有個(gè)例外:
當(dāng)用distinct玫芦、group by浆熔、order by時(shí),此時(shí)不同的null值被視為相等計(jì)算桥帆。
最重要的是医增,在mysql中慎皱,0和null代表假,其它的任何值都代表真
所以回頭看最開始的例子叶骨,當(dāng)我們的where條件為name!='chen'時(shí)茫多,它與id=1的行進(jìn)行比較,即測(cè)試:
'chen'!='chen'
這個(gè)測(cè)試結(jié)果為0忽刽,為假天揖,所以id=1這一行就不會(huì)被查出來。接下來再測(cè)試:
'zhang'!='chen'
這個(gè)測(cè)試結(jié)果為1跪帝,為真宝剖,所以id=2這一行就可以被查出來。接下來再測(cè)試:
NULL!='chen'
這個(gè)測(cè)試結(jié)果為NULL歉甚,為假,所以id=3這一行就不會(huì)被查出來扑眉。
所以最終的結(jié)果就只有id=2這一行的數(shù)據(jù)被查出來了纸泄。
那如果要達(dá)到我們的目地怎么辦?
3306>select * from t1 where name!='chen' or name is null;
+------+-------+
| id | name |
+------+-------+
| 2 | zhang |
| 3 | NULL |
+------+-------+
2 rows in set (0.01 sec)
或
3306>select * from t1 where ifnull(name,0)!='chen' ;
+------+-------+
| id | name |
+------+-------+
| 2 | zhang |
| 3 | NULL |
+------+-------+
2 rows in set (0.00 sec)
推薦用第一種方法腰素。
因?yàn)閙ysql對(duì)了null列的查找是有查詢優(yōu)化的:
3306>explain select * from test a where a.code='AAAAAA' or a.code is null\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: a
type: ref_or_null
possible_keys: code
key: code
key_len: 21
ref: const
rows: 73603
Extra: Using index condition
1 row in set (0.01 sec)
而第二種在列上加上函數(shù)的查詢時(shí)索引是不起作用的聘裁。
其它注意事項(xiàng)
用order by ... asc時(shí),null值會(huì)被放在最前面弓千,而用order by ... desc時(shí)衡便,null時(shí)會(huì)被放在最后面,相當(dāng)于null是一個(gè)無窮小的值洋访。
聚合函數(shù)如count(),min(),sum()是忽略null值的镣陕。唯一的例外是用count(),如
SELECT COUNT(), COUNT(age) FROM person;
如上語句是第一個(gè)count(*)是計(jì)算person表總行數(shù)姻政,而第二個(gè)是計(jì)算person表age列非null的行數(shù)在MyISAM呆抑、InnoDB和MEMORY引擎中,是可以在包含null值的列添加索引的,而在其它引擎中則必須聲明為not null才可以添加索引
當(dāng)用load data infile時(shí),空的或者沒有的列將用空字符''代替汁展,如果要導(dǎo)入null值鹊碍,需要在數(shù)據(jù)文件里用\N來表示。
如果你往timestamp插入null值食绿,則當(dāng)前時(shí)間會(huì)被插入侈咕,如果一個(gè)自增列插入null值,下一個(gè)自增值將會(huì)被插入器紧。