group by 字句
GROUP BY 子句根据给定列或者表达式的每一个不同的值将表中的行分成不同的组。使用组函数返回每一组的统计信息
分组的字句,用于对指定列进行分组
可以实现大组再分小组的操作
例3: 统计每个球队中每个球员所赢得的总局数
SELECT teamno, playerno, sum(won)
FROM matches
GROUP BY teamno, playerno;
带有排序的分组
如果分组列和排序列相同,则可以合并group by和order by子句
例6: 得到每个球队的编号和比赛总场数,结果按球队编号降序排序
SELECT teamno, count()
FROM matches
GROUP BY teamno
ORDER BY teamno DESC;
可以把desc(或者asc)包含到group by子句中简化
SELECT teamno, count()
FROM matches
GROUP BY teamno DESC;
例如:
查看每只球队每个球员的获胜次数
group by也可以使用函数
group by 和order by可以进行合并,将排序类型的标识(desc、asc)放到group by字句即可
MySQL当中select单独出现的列可以不作为分组列,此时单独的列会随机的返回值。建议通过设置sql_mode系统变量的值为ONLY_FULL_GROUP_BY来强制mysql和其它数据库一样,遵循该规则(推荐)
Group by 子句的规则
**1、出现在SELECT子句中的单独的列,必须出现在GROUP BY子句中作为分组列。这条规则适用于其它数据库,但是不适用于MYSQL。**例如:
SELECT town, count()
FROM players
GROUP BY sex;
ERROR 1055 (42000): ‘players.town’ isn‘t in GROUP BY
2、分组列可以不出现在SELECT子句中
3、分组列可出现在SELECT子句中的一个复合表达式中
例7: 得到以美分为单位的罚款额的列表
SELECT cast(amount * 100 AS SIGNED INTEGER) AS amount_in_cents
FROM penalties
GROUP BY amount;
**4、如果GROUP BY后面是一个复合表达式,那么在SELECT子句中,它必须整体作为一个表达式的一部分才能使用。**例如,如果group by playerno2,那么表达式playerno2,(playerno2)-100,和mod(playerno2,3)-100都可以出现在SELECT子句中,但是playerno,2playerno,playerno*100不可以
3.MySQL特有的函数:group_concat()
将得到的结果以逗号作为分割,返回给用户。
MYSQL特有的组函数。该函数的值等于属于一个组的指定列的所有值。这些值一个挨一个的放置,以逗号隔开,并且以字符串表示。
例8:对于每个球队,得到其编号和所有球员的编号
SELECT teamno, group_concat(playerno)
FROM matches
GROUP BY teamno;
如果没有group by子句,group_concat返回一列的所有值
例9: 得到所有的罚款编号列表
SELECT group_concat(paymentno)
FROM penalties;
系统变量group_concat_max_len控制该函数返回的最大字符长度,默认1024。可通过set语句修改:
Set @@group_concat_max_len=7;
用来要求在一条GROUP BY子句中进行多个不同的分组
例10: 得到每个球员的编号,罚款总和以及所有球员的罚款总和
SELECT playerno, sum(amount)
FROM penalties
GROUP BY playerno
UNION ALL
SELECT NULL, sum(amount)
FROM penalties;
第一个查询按照每个球员分组,第二个查询按照所有球员分组
改写上例:
SELECT playerno, sum(amount)
FROM penalties
GROUP BY playerno WITH ROLLUP;
with rollup表明在按playerno分组之后,还需要另一个分组。本例中,就是根据所有行分组
一般来说,如果有子句GROUP BY E1,E2,E3,E4 WITH ROLLUP,那么将分别执行以下分组:[E1,E2,E3,E4]、[E1,E2,E3]、[E1,E2]、[E1]、[]。[]表示所有行都分在一组中
例11:按照球员的性别和居住城市,统计球员的总数;统计每个性别球员的总数;统计所有球员的总数
SELECT sex, town, count(*)
FROM players
GROUP BY sex,town WITH ROLLUP;

对分组结果进行过滤
不能使用WHERE子句对分组后的结果进行过滤
不能在WHERE子句中使用组函数
例: 得到那些多于一次罚款的球员的编号
SELECT playerno
FROM penalties
WHERE count() > 1
GROUP BY playerno;
错误代码: 1111
Invalid use of group function
因为WHERE子句比GROUP BY先执行,而组函数必须在分完组之后才执行
3.having字句
语法:
SELECT select_expr [, select_expr …]
FROM table_name
[WHERE where_condition]
[GROUP BY {col_name | expr} [ASC | DESC], … [WITH ROLLUP]]
[HAVING where_condition]
专门用来对分组后的结果进行过滤
HAVING可以单独使用而不和GROUP BY配合
HAVING子句中可以使用组函数
例1: 得到那些多于一次罚款的球员的编号
SELECT playerno
FROM penalties
GROUP BY playerno
HAVING count() > 1;
如果只有HAVING子句而没有GROUP BY,表中所有的行分为一组
例3: 得到所有罚款的总和,要求总和大于250元时才显示
SELECT sum(amount)
FROM penalties
HAVING sum(amount) > 250;
HAVING子句中的列,要么出现在一个组函数中,要么出现在GROUP BY子句中。否则出错
SELECT town, count(*)
FROM players
GROUP BY town
HAVING birth_date > ‘1970-01-01’;
错误代码: 1054
Unknown column ‘birth_date’ in 'having clause’