场景:需要导出签到达到15天的用户id,在业务中,用户每签到一天就新增一条记录,其中通过round字段来区分当前是第几轮签到,如用户第一天签到,该条记录round为0;第二天、第三天未签到,第四天又签到了,则新增一条记录,round为3。此时该表中该用户一共有2条签到记录。
由于没有round未必是连续的,签到15天就无法直接通过round>14判断,同时,由于是要找出所有用户中满足条件的用户id,且每签到一天就有一条记录,因此考虑需要使用group by对用户id进行分组,然后统计每组有多少条数据即该用户签到多少天。
select mid, count(1) from task_user_state where task_id = 1 and count(1) >14 group by mid
上面那条语句看起来没什么问题,从表中找出count(1)大于14的mid及记录数,但是在本地执行的时候发现报了个1111的错误,即#1111 - Invalid use of group function,无效的group函数使用。查阅资料,发现group by有一个特点,当我们group by一列之后,不能同时又去count这一列,会发生冲突。如果想要count,只能count别的列。因此,不能对分组后的列进行统计。
既然冲突了不能统计,那就去掉那个条件试一试:
select mid, count(1) from task_user_state where task_id = 1 group by mid order by count(1) desc
果然,错误没了,但是如果数据量太大的话,只能手动截取满足条件的mid,似乎可以满足需求。
但是手动截取肯定不是最佳的,再加一个过滤条件,MySQL允许过滤分组,使用having,因此:
select mid from task_user_state where task_id = 1 group by mid having count(1) > 14
执行,没有错,那就决定是它了~
总结一下:
1. Where完成的是行过滤,having完成的是分组过滤。当然也可以同时使用,但是having要放在group by之后
2. group by与聚合函数(sum,count...)配合使用时,可以进行分组后的计算
3. 扩展:group by与聚合函数及非聚合字段使用时,非聚合字段的取值时第一个匹配到的字段内容。