SQL避坑指南之NULL值知多少?

0 引言

    SQL NULL(UNKNOW)是用来代表缺失值或无意义值的术语,在表中的NULL值是显示为空白字段的值,用作不知道数据的具体值,或者不知道数据是否存在,或者数据不存在等情况。NULL值在SQL中普遍存在,想必大多数程序员对其有所了解,但是对于NULL值在SQL中贯穿体现及相关细节,是否会有人注意到呢?本文将对SQL中NULL值的一些使用细节进行研究,让你在使用过程中避开NULL值的坑,从而更加灵活的使用SQL语言。

1 数据准备

(1)创建测试表

drop table if exists table_null_test;
create table table_null_test as
select 1 as id,'guozixuezhang' as name union all
select 2 as id,'xiaoyanjing' as name union all
select '' as id,'' as name union all
select 4 as id,'' as name union all
select null as id,null as name union all
select 6 as id,null as name union all
select null as id,' ' as name 
;

(2)查看数据

select * from table_null_test

    数据查看如下:

2 NULL值用途

(1)被定义为缺失值

(2)被定义为无意义的值

(3)不存在的值

(4)不确定性值

(5)建表语句中作为非空约束

(6)常常作为非匹配值(如join,case when语句中)

3 NULL值研究

(1)NULL值的比较

对NULL进行判断处理时,只能采用IS NULL或IS NOT NULL,而不能采用=, <, <>, !=这些操作符!

例如如下操作:

select * from table_null_test where id <> '1';

该条语句正常返回应该是6条语句,但结果只有4条也就是说id为null的值并没有返回,说明null的判断有其特殊的语法。我们采用下面的语句进行试验:

select * from table_null_test where id <> '1' or id is null;

  查看结果:

可以看出结果是和我们的预期是相符的。

我们对比一下选出name不为null的两种sql表示方法:

第一种:

select * from table_null_test where name != null;

没报错但结果明显不对

第二种:

select * from table_null_test where name is not null;

 可以看到结果符合预期。

(2)NULL与聚合函数的运算

count(*)操作时会统计null值,count(列名)会忽略null值
与max(),min(),avg()函数作用时都会忽略NULL值计算
事实上NULL除了count(*),与聚合函数运算时均会忽略null值

 因此一般正确的统计某个字段的条数应该是,count(字段名)

 包括null值:

select count(*) from table_null_test

 结果如下:7条

 不包括null值

select count(name) from table_null_test

结果如下:5条

与avg()函数的运算

SELECT avg(id) FROM `table_null_test`

计算结果2.6,和为sum=1+2+4+6=13,count=5,说明计算时候忽略了null值。相当于sum(id)/count(id)。同理max(),min()函数等也会忽略null.这里计算特别注意avg(),因为计算时条数发生变化。如果希望null值参与运算,可以用case when,NVL(),coalesce()函数进行转换。 例如求均值,希望null值参与运算,可以按照如下方式进行计算。

SELECT avg(coalesce(id,0)) FROM `table_null_test`

  计算结果如下:

(3) NULL值参与算数运算

与null值进行算数运算时,其操作结果都为null

 

(4) NULL值参与group by的分组计算

此时NULL值会被单独作为一个列进行分组,而不会被忽略

 具体参考下面的例子:

SELECT name,count(*) FROM `table_null_test` group by name

(5)NULL值参与distinct计算

此时NULL会参与计算,会进行排重,过滤后会有一个NULL值

 例如:

SELECT distinct(name) FROM `table_null_test`

结果如下:

可以看到NULL值被排重。

(6)NULL值参与排序运算

  对NULL值进行排序时会参与运算,会对NULL值进行排序,在Mysql中按升序排序时候NULL值被排在最前面,降序排序时NULL只被排在最后。(不同的数据库可能稍有差异)

SELECT name FROM `table_null_test` order by name desc

上面的结果对name字段进行了降序排序 ,可以看到NULL被排在最后。

(7)大部分功能函数与NULL值作用时都会返回NULL。

    如concat()函数等

select concat(name,'_',id) from table_null_test

结果如下:

(9) NULL在建表语句中作为非空约束

(10)NULL作为非匹配值。如join语句中,case when条件匹配中

(11)NULL值的转换

如果想要NULL参与运算,往往需要对NULL进行转换,其转换主要有以下两个函数完成
NVL()函数
COALESCW()函数
Mysql中的IFNULL()函数等

以mysql中为例进行演示

SELECT coalesce(name,0) FROM `table_null_test`
SELECT ifnull(name,0) FROM `table_null_test`

结果如下:

(12)NULL值的底层存储

  对于NULL值而言是占用存储空间的,hive中以'/N'进行存储。下面我们以Mysql数据库为例进行试验验证NULL值大小

select name,length(name) from table_null_test

   查看结果可以看出,Mysql中NULL其实是占用空间的,用一个标志给出,这也验证了设计表时的一句话“在创建表的时候尽量把字段的默认值设置成 not null,除非你想存储null”。而空值('')是不占用空间的。这也说明了NULL是有东西,但不显示只是给个标志,代表无意义的值等,而''就表示空值里面没有值。

(13)NULL与''的区别

   1)NULL在聚合函数中会被忽略,而''不会被忽略。这点在进行统计的时候需要特别注意

   2)对于NULL的判断需要is null 或is not null,而''则需要=或!=,<>

  3)NULL占用存储空间,''不占用存储空间。

     在创建表的时候尽量把字段的默认值设置成 not null,除非你想存储null;因为在mysql中为null的的字段不会走索引,做统计的时候也不会被统计进去,如果想统计进去必须做特定的处理,这样做比较复杂。可以给字段的值设置成0、一个特殊的值或者一个空串代替空值。

4 小结

    本文充分分析、研究了NULL值的意义及相关用法,对NULL值的一些需要注意的细节进行了归纳总结,本文对于认识NULL值、设计表及进行SQL数据分析时具有重要意义。

发布了18 篇原创文章 · 获赞 208 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/godlovedaniel/article/details/104860042