今天写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:

 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐