在使用数据库做业务开发时,我们经常遇到一个关键字"null"
;那null
和""
有什么区别呢?null
通常用在什么地方呢? 在使用null
的过程中,经常会遇到一些让我们摸不着头脑的问题。下面这些问题,你都遇到过吗?
在定义表结构时,会经常遇到类似下面的字段定义:
`name` varchar(45) not null default '' comment '名称'。
上面的语句表示:定义一个名称为name
的字段,字段的默认值为‘’
。当向表中新增数据的时候,该字段值不能为null
,如果该字段的值没有明确指定的话,那么保存的值,默认为空字符串。
为什么不建议把字段的默认值设置为null呢?
其实null
表示的是一种特殊含义,表示 “未知” 的意思,是一个 不确定的值 ,它不像空字符串,虽然空字符串表示字段值为空,但是它的含义是明确的,是确定的。
为了方便描述,建立如下的表结构:
CREATE TABLE `t` ( `id` int(11) NOT NULL not null auto_increment, `a` int(11) , `b` int(11) not null DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB;
定义一个名称为t
的表,表中有三个字段,主键id
,int
类型的字段a
,没有指定任何默认值。int
类型字段b
,默认值为0
。
在表t
中,字段a
的定义,没有指定默认值,那么该字段的默认值就是null
。
可以通过插入一条数据进行验证:
insert into t (id),value(1);
然后通过查询语句进行查看:
select * from t;
可以看到,字段a
的值为null
,字段b
的值为0
.
从返回结果中,我们可以看到a
的值,的确为null
,那么我们在业务中如何判断这个值是否为null
呢?换句话说,应该在where
后面使用什么条件,来判断字段值为null
呢?
在讨论null
的判定方式前,需要先明确where
后的条件表达式,可能返回的值。我们知道,where
后的条件是一个boolean
表达式,通常返回的结果有两种:true
或false
。如果条件表达式返回为true
,那么就把满足条件的数据集返回,否则不返回任何数据。
如果在判断条件中出现了null
关键字后,条件表达式返回值,可能还会有第三种,也就是"未知"
,那where
接受到"未知"的返回结果后,会怎么处理呢?
where
对"未知"的处理和false
的处理时一样的,也不会返回任何结果。
有时候,我们已经知道某个字段的值为null
,但是我们如何进行判定呢?这里有两种方法:
select * from t where a= null; select * from t where a is null;
第一条sql
的返回结果:
第二条sql
的返回结果:
根据返回的结果,可以发现第二种可以满足我们的需求。那么为什么第一种方式不可以,而第二种方式可以呢?
对于第一种方式,where a=null;
表示的含义是:未知 等于 未知 吗?
细品一下,好像不确定,因为不知道"未知"代表什么值,所以不好判定。那么对于这种不确定的结果,返回值也是"未知"。而where
对"未知"的处理和false
相同,不返回任何结果。
而对于第二种方式,where a is null;
表示的含义是:a字段的值是未知的吗?
这个比较好回答,a
的值是null
,的确是未知的。所以此时 where
的返回值是true
。将满足条件的数据返回。
所以,在判断一个字段的值是否是未知的,应该使用 is null,不能使用 = null;
结合where
对条件的处理,我们发现条件的返回结果为false
或null
时,数据库引擎对其处理都是一样的。那是不是就没有必要对false
和 null
进行区分了呢?
其实是有必要的,虽然where
对两种处理结果的处理方式是一样的。但是呈现出的语义却是完全不同的,当where
收到返回值null
时,此时数据库引擎不知道该怎么处理,所以就返回了一个空的数据集,而收到false
时,表示条件不满足,需要返回一个空的数据集。
除此之外,对于返回值为null
的条件,我们在其前面添加 not
,和在返回值为false
的条件前添加not
,条件的返回值是不同的。
举例如下:
select * from t where b = 1; select * from t where b = null;
第一条sql的执行结果:
第二条sql的执行结果:
上面两个语句中,b=1
返回值为false
,因为b
的值为0
。b=null
返回值为 null
,因为b=0
,null
表示未知,null
有可能是0
,也可能不是0
。b=null
的返回值还是 null
。所以上面两条sql
的返回结果都是空数据集。
如果给上面两个sql
的判断条件前加上not
后,返回结果会有影响吗?
我们继续验证下:
select * from t where not (b = 1); select * from t where not (b = null);
第一条sql
的执行结果:
第二条sql
的执行结果:
根据返回的结果可以看到,第一条sql
返回了一条数据,说明 not (b=1)
返回true
,因为 b=1
为 false
。
而第二条sql
的返回结果依旧空数据集。因为 b=null
是 null
,是未知
,not (null)
的结果仍然是未知
。
在使用 in
的时候,遇到了null
会产生什么结果呢?对于下面这些sql
,他们的执行结果是怎样的呢?
(1) select * from t a in (0,1,null);
返回结果为空数据集,因为 a
是null
,数据库引擎无法判断,一个值未知的值,是否存在于(0,1,null)
,所以数据库引擎对其的处理和false
一样。
(2) select * from t b in (0,1,null);
返回结果不为空,因为 b
的值是0
,可以明确的确定,b
的确存在于(0,1,null)
中。
(3) select * from t where b in (1,2,null);
返回结果为空,因为null
的值未知,有可能为0
,也有可能不是0
,所以数据库引擎,无法判断是否存在,所以条件的返回值是null
,sql
的返回结果为空。
其实,明确了null
表示未知
的含义,那么在遇到null
的场景,都可以把null
表示的未知
语义代入
进去,再结合where
对未知的处理机制,以前很多不确定的问题都可以迎刃而解了。