今天写sql的时候发现了一些小细节。
用count(1)统计符合特定条件的用户数量时,利用月份进行分组。当没有符合条件的用户时,count(1)会返回0。
但是下面的结果却不为0:
select count(1) num
from users
where Address='Shanghai'
and Id>10010
group by Month;
很有趣的是,结果是空记录。
在多次尝试后,我发现把group by去掉之后,count(1)才会返回0:
select count(1) num
from users
where Address='Shanghai'
and Id>10010;
这种现象,我认为是因为count在group by之后执行,但是由于筛选后的临时表纪录为空,group by产生的临时表不存在,所以统计出的结果是null而不是0。
值得一提的是,这种情况下使用IFNULL函数也没有效果,因为空记录并不等同于NULL。
这种情况其实在工作中有可能会出现,所以在进行分组统计时,最好还是处理一下。
这里我采用了嵌套子查询来规避:
select count(1) num
from (
select month,name
from users
where Address='Shanghai'
and Id>10010
group by Month,Name) a;
这里我猜测是因为子查询自动生成了一个空临时表,因此count(1)才为0。
考虑到对空表、含有null的表使用group by及分组函数存在的问题,我也进行了尝试,以下是我的部分结果:
1. 对空表
- 使用count(*)/count(1)/count(列名)时,返回0。若再加上分组(group by) ,对空表会返回空表(由于group by产生的临时表不存在)。
- 使用sum/avg/max/min(1)或sum/avg/max/min(列名),返回null;若再加上分组(group by) ,对空表会返回空表(由于group by产生的临时表不存在)。
- 在函数的返回值中,这一点会影响结果:若使用group by,count()返回null;不使用group by,则count()返回0。
第一张无group by,第二张有group by:
2. 对列a中均为null或全表均为null的表:
- 使用count(a),无论有无group by,都返回0;
- 使用count(1)/count(*),无论有无group by,都会返回总行数。
- 使用sum/avg/max/min(a),无论有无group by,都会返回null;
- 使用avg/max/min(1),无论有无group by,都会返回括号中的数字。
- 使用sum(1),无论有无group by,都会返回(行数*括号中的数字)。
第一张无group by,第二张有group by:
3. 对列b存在多个null(不全为null)的表:
- 使用count(b),返回不为null的总行数。当对列b使用group by时,null与非null会被区分开,返回结果中,null成为一个分组,count(b)等于0(不管其他列是否有值),其他不为null的count(b)等于各自的行数。
- 使用count(1)/count(*),会返回总行数。当对列b使用group by时,null与非null会被区分开,返回结果中,null成为一个分组,count(1)/count(*)等于列b中为null的行数,其他不为null的则会得出各自的行数。
- 使用sum/avg/max/min(b),返回不为null的数值总和/平均值/最大值/最小值。当对列b使用group by时,null与非null会被区分开,返回结果中,null成为一个分组,sum/avg/max/min(b)等于null(不管其他列是否有值),其他不为null的sum/avg/max/min(b)等于相应的和/平均值/最大值/最小值。
第一张无group by,第二张有group by: