示例中涉及的表、数据参考链接进行创建:
https://www.jianshu.com/p/480d20bf2370
上一篇文章中已经对汇总数据的几个聚集函数进行了介绍,聚集函数使我们能够对行进行计数,计算和与平均数,获得最大值、最小值而不用检索所有数据,例如在之前的例子中我们返回指定供应商提供的产品数目:
但如果要返回每个供应商提供的产品数目怎么办?或者返回只提供单项产品的供应商所提供的产品,或者返回提供10个以上产品的供应商怎么办?
这就是分组显身手的时候了,分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算
创建分组:
如下的例子中使用group by 进行创建分组并统计:
上面的select语句制定了两个列,vend_id为产品供应商的ID,num_prods为计算字段(由count(*)函数建立),group by 子句指示MySQL按vend_id排序并进行数据分组,这导致对每个vend_id而不是整个表计算num_prods一次。从输出中可以看到,供应商1001有三个产品,供应商1002有两个产品,供应商1003有7个产品,而供应商1005有两个产品。
因为使用了group by ,就不必指定要计算和估值的每个组了,系统会自动完成,group by 子句指示MySQL按分组数据,然后对每个组而不是整个结果集进行聚集。
使用group by 需要注意以下几点:
/*/group by子句可以包含任意数目的列,从而实现对分组的嵌套
/*/group by子句中每个列都必须是检索列或有效的表达式,但不能是聚集函数
/*/除聚集计算语句外,select语句中的每个列都必须在group by子句中给出
/*/如果分组列中包含NULL值,则将NULL作为一个分组返回
/*/group by子句必须出现在where子句之后,order by 子句之前
过滤分组:
除了能用group by进行分组外,MySQL还允许过滤分组,规定包括哪些分组,排除哪些分组。例如可能需要列出至少有两个订单的所有顾客,为了获得这种数据,必须基于完整的分组,而不是个别分组。
这条select语句的前面部分类似于上面的创建分组语句,最后加了一个having子句,他过滤count(*)>=2(两个以上的订单)的那些分组。
注意:having与where是有区别的,where在数据分组前进行过滤,having在分组后进行过滤,也就是说where排除的行是不包含在分组中的。
那么有没有一条语句中同时使用having子句和where子句的需要呢?答案是有的,假如想对上面的语句进一步过滤,使他返回过去12个月内具有2个以上订单的顾客,那么此时就可以在原有的基础上增加一条where子句,然后在用having子句过滤出具有两个以上订单的分组。
上面的这条语句,它列出了具有2个以上、价格为10以上的产品的供应商,在这条语句中,先是使用了select,然后使用where过滤出所有prod_price至少为10的行,然后按vend_id进行分组,最后having子句过滤出计数(count(*))至少为2的分组。如果没有where子句将多检索出两行,如下所示:
分组和排序:
在实际使用的时候,group by 和order by 常常是完成相同的工作,但他们之间又有着本质的不同:
为说明group by与order by的用法,请看下面的例子,检索总计订单价格大于等于50的订单的订单号和总计订单价格:
可以看出,我们已经正确检索出总计订单价格大于等于50的订单的订单号和订单价格,但此时返回的的结果是无序的,要想得到有序的数据,那么此时就需要使用order by子句
在上面的这个例子中,group by子句用来按订单号(order_num列)分组数据,以便sum(*)函数能够返回总计订单价格,having子句过滤数据,使得只返回总计订单价格大于等于50的订单,最后用order by子句排序输出。
select子句顺序:
本系列文章中我们介绍了多个select子句的使用方法,而select中子句的使用是要遵循一定顺序的,其规则如下所示:
**********书山有路,学海无涯,无数个孤独的夜晚,需要一点小小的成就感!**********