原创文章,转载请注明出处:http://www.cnblogs.com/weix-l/p/7521278.html;
html
如有错误,请评论指出,谢谢!mysql
1. 聚合函数(Aggregate Function)sql
MySQL(5.7 ) 官方文档中给出的聚合函数列表(图片)以下:数据结构
详情点击https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html 。函数
除非另有说明,不然聚合函数都会忽略空值(NULL values)。测试
2. 聚合函数的使用spa
聚合函数一般对 GROUP BY 语句进行分组后的每一个分组起做用,即,若是在查询语句中不使用 GROUP BY 对结果集分组,则聚合函数就对结果集的全部行起做用。为说明聚合函数的使用,现建立测试表 member 进行测试,member 的数据结构以下(使用 SELECT * FROM member 查询所得):3d
1)对结果集直接使用聚合函数code
例如,使用聚合函数SUM () 计算全部会员(member) 的会费总和,则可以使用:htm
SELECT SUM(fee) AS total_fee FROM member #计算全部会员会费总和
查询结果为:
SUM 函数会对所有字段列 fee 进行求和。固然,也能够求平均值、最大值等。
此外,也可使用 WHERE 语句进行限定条件的聚合查询。例如,若是要查询 country 为 China 的会员会费之和,则为:
SELECT SUM(fee) AS China_total_fee, country FROM member WHERE country = 'China'
结果显示以下:
2)GROUP BY 对结果集分组后使用聚合函数——组内聚合
——将字段值相同的记录归为一组,可用COUNT(*) 统计组内成员个数;
——以分组为单位,对组内每一个成员使用聚合函数进行统计,即聚合函数是关于分组成员的函数。
试想,若是要从测试表中查询每一个国家的会费总和呢?每一个国家的会费,即先将全部结果集按 country 字段进行分组,country 值相同的行归为一组,而后以组为单位进行求和,这样查询的结果记录数等于分组字段不一样值的个数。总共有来自三个国家(China, US, UK)的会员,因此分组聚合查询的结果记录数为3:
#查询每一个国家的会费之和
SELECT SUM(fee) AS country_group_total_fee, country FROM member GROUP BY country
该查询语句会计算每一个国家的会费之和,而后展现按每一个国家分组的查询结果:
标准SQL( standard SQL) 和 MySQL 都提供 HAVING 语句对使用 GROUP BY 分组以后的结果进行条件筛选并产生新的结果集。例如,对于前述 1)中查询中国会员会费总和的问题,可使用HAVING 语句:
#使用HAVING语句查询中国会员会费总和
SELECT SUM(fee) AS country_group_total_fee, country FROM member GROUP BY country HAVING country = 'China'
结果和上面同样:
这种方法与前述 1)中直接使用WHERE进行限定相比有些多此一举,为何呢?由于 country 在此是分组字段(group column),对分组字段使用 HAVING 再次进行限定则就显得分组毫无心义,由于这时彻底能够经过使用 WHERE 进行筛选后直接求和实现。那么,能使用非聚合列(nonaggregated column) 为限定条件吗?答案是,不只没有意义,并且不容许。非聚合列指的是没有用聚合函数而是要查询的表自己的字段,由于使用 GROUP BY 分组查询后的聚合结果列中根本就不包含非聚合字段列,因此在解析SQL语句时根本找不到这个字段。好比,当你想获取每一个国家性别为 man 的会员的会费之和时可能尝试在上面这个语句中使用 HAVING 对 sex 进行限定,像下面这样:
#错误:尝试使用HAVING 语句对非聚合字段进行限定
SELECT SUM(fee) AS country_group_total_fee FROM member m GROUP BY country HAVING m.sex = 'man'
执行后会报错 Err 1054:
[Err] 1054 - Unknown column 'm.sex' in 'having clause',提示未知的列m.sex,即便此处使用别名进行说明也不行。那么如何实现查询每一个国家性别为 man 的会员的会费之和呢?固然仍是使用WHERE 语句在 GROUP BY 进行分组以前就进行限定:
#在分组以前使用 WHERE 进行条件筛选
SELECT SUM(fee) AS country_group_total_fee, country FROM member WHERE sex = 'man' GROUP BY country
产生下面结果:
因此,HAVING 不能对分组自己起做用,但能够对分组后的结果进行查询限定,而限定的条件只能为聚合列(aggregated column),聚合列指的是在 SELECT 列 (SELECT list)中使用聚合函数产生的列,例如,此处的SUM(fee) 就是聚合列。在HAVING 中对聚合列进行限定,能够获取知足必定条件的聚合列结果。例如,在上面获取每一个国家会员费用之和后再限定查询哪些会员费用之和超过10000,则可使用下面的SQL 语句:
#查询会员费总和超过10000 的国家
SELECT SUM(fee) country FROM member GROUP BY country HAVING SUM(fee) > 10000
其结果就只剩下中国了:)
这是在标准SQL语句中的语法。在MySQL中扩展了HAVING 的用法,使其能够接受聚合列的别名做为限定条件,例如上面的要求使用别名的查询语句为:
#在HAVING 中使用别名
SELECT SUM(fee) AS country_group_total_fee, country FROM member GROUP BY country HAVING country_group_total_fee > 10000
其结果仍为:
3)GROUP BY 按多个分组字段分组后使用聚合函数——细分组内聚合
若是使用一个分组字段分组后的聚合结果记录数等于该分组字段不一样值的个数,那么,使用多个分组字段之后呢?例如,在上面的查询的基础上,若是想要查询每一个国家男、女分别的会费总和时,可使用下面的语句:
#查询每一个国家男、女会员的总和会费
SELECT SUM(fee) AS sex_and_country_group_total_fee, country, sex FROM member GROUP BY country,sex
结果以下:
从上面的结果能够看出来,“中国的男性会员出的总会费最多,而英国的男性会员的总会费最少”。总共三个国家,若是只按国家(country) 进行分组,只有三条记录,若是再按性别 (sex) 分,则会在分组后的每一个组(也即每一行、每一条记录)里按性别的不一样再进行细分,由于性别值只有两种,因此每一个国家的分组又被分红两小组,则三个国家总共就有6小组(6 = 3 × 2),这样最终也就会有6条记录,如上图示。
为了解每一个细分小组的个数,在SELECT 查询列的最后加上计算分组个数的聚合函数 COUNT(*):
#多分组字段分组,并统计每组个数
SELECT SUM(fee) AS sex_and_country_group_total_fee, country, sex, COUNT(*) AS row_num FROM member GROUP BY country, sex
结果以下:
上面的结果默认按靠近GROUP BY 的顺序进行排序,但若是要指定排序一句,则可以使用ORDER BY ,例如,对上面的结果按 sex 排序:
#将分组结果按sex 排序
SELECT SUM(fee) AS sex_and_country_group_total_fee, country, sex, count(*) AS row_num FROM member GROUP BY country, sex ORDER BY sex
结果以下:
若是用其余字段对结果再进行细分呢?原理与上述两个字段进行分组时同样的,只是分组的深度越多,很明显结果的记录行数也越多,但无论怎样,你会发现每一条分组后的结果都是不同的,这正是分组结果的特征,由于ORDER BY 自己就具备聚合功能,每一个聚合列的结果是经过分组归类的结果,因此只有一条记录。
那么,若是用表的 主键 或 非空惟一性字段 进行分组,结果会怎样呢?好比,在本测试表中,id 是其主键,name 是非空的具备惟一性约束的字段,下面分别是以 id 和 name 进行分组的MySQL 语句和结果:
#以主键id进行分组
SELECT SUM(fee) AS sex_and_country_group_total_fee, id, COUNT(*) AS row_num FROM member GROUP BY id
结果以下:
#以非空惟一性约束字段进行分组
SELECT SUM(fee) AS sex_and_country_group_total_fee, name, COUNT(*) AS row_num FROM member GROUP BY name
结果以下:
很显然,这两种分组的结果中聚合函数结果列是同样的,每组的结果记录行数也同样,并且都为1,这说明按主键或非空惟一性约束字段进行分组其结果相同,且结果就是表的所有每一行记录。这样作可能没有太大意义,但有助于理解 GROUP BY 分组的原理。
3. 总结
1) 可直接对某个字段使用聚合函数,也可用 WHERE 语句筛选后对某个字段使用聚合函数;
2) 聚合函数一般做用于使用 GROUP BY 分组后的分组成员,用于统计每一个分组的数据;
3) 不能对没有使用 GROUP BY 分组的聚合函数使用 HAVING 进行限定;
4) 可对使用 GROUP BY 分组查询后的结果使用 HAVING 进行限定,其限定条件最好为聚合函数列(自己或其余聚合函数);
5) 可在使用 GROUP BY 分组前使用 WHERE 对结果进行筛选,在分组后使用 HAVING 对聚合函数列进行限定;
6) 可以使用 ORDER BY 对结果按照某个字段(任意字段或列,使用 GROUP BY 分组时也可以使用聚合函数列)进行排序;
7) 当按照主键或非空惟一性约束字段进行分组时,其结果为整个表的所有记录。
4. 参考文献
[1]. MySQL 官方文档 URL: https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html