本文主要介绍 SQL 中 GROUP BY 语句的用法。
1 概述
GROUP BY 语句通常用于结合聚合函数(如COUNT()、MAX()等),根据一个或多个列对结果集进行分组。
从字面上来理解,GROUP 表示分组,BY 后接字段名,表示根据某个字段进行分组。
一般情况下,GROUP BY 必须要配合聚合函数一起使用,通过使用聚合函数,在分组之后可以对组内结果进行计数(COUNT)、求和(SUM),求平均数(AVG)操作等。
常用聚合函数包括:
- count() —— 计数
- sum() —— 求和
- avg() —— 平均数
- max() —— 最大值
- min() —— 最小值
2 用法示例
现在数据库表内容如下:
mysql> select * from roles;
+---------+------------+----------+---------------------+
| role_id | occupation | camp | register_time |
+---------+------------+----------+---------------------+
| 1 | mage | alliance | 2018-12-03 16:11:28 |
| 2 | paladin | alliance | 2018-11-30 16:11:28 |
| 3 | rogue | horde | 2018-12-01 16:11:28 |
| 4 | priest | alliance | 2018-12-02 16:11:28 |
| 5 | shaman | horde | NULL |
| 6 | warrior | alliance | NULL |
| 7 | warlock | horde | 2018-12-04 16:11:28 |
| 8 | hunter | horde | NULL |
+---------+------------+----------+---------------------+
8 rows in set (0.00 sec)
mysql>
我们针对上表进行一些 GROUP BY 用法演示。
2.1 结合聚合函数
首先,我们不使用聚合函数,只使用 GROUP BY,查询结果如下:
mysql> select camp,role_id,occupation,register_time from roles group by camp;
+----------+---------+------------+---------------------+
| camp | role_id | occupation | register_time |
+----------+---------+------------+---------------------+
| alliance | 1 | mage | 2018-12-03 16:11:28 |
| horde | 3 | rogue | 2018-12-01 16:11:28 |
+----------+---------+------------+---------------------+
2 rows in set (0.00 sec)
mysql>
从上述查询结果能够看到,当不使用聚合函数时,GROUP BY的结果是分组内容中的第一组查询结果。
当然,在实际使用中,我们通常都需要将聚合函数与GROUP BY用法结合使用,来实现某种目的。
例如,我们想查找“联盟和部落阵营中所有角色最早的注册时间”,则可以通过如下语句实现:
mysql> select camp,MIN(register_time) as register_time from roles group by camp;
+----------+---------------------+
| camp | register_time |
+----------+---------------------+
| alliance | 2018-11-30 16:11:28 |
| horde | 2018-12-01 16:11:28 |
+----------+---------------------+
2 rows in set (0.01 sec)
mysql>
上述查询结果表明,通过使用聚合函数“MIN()”,我们找到了每个阵营中最早的注册时间。
2.2 HAVING子句
HAVING 子句可以让我们筛选通过 GROUP BY 分组后的各组数据。
衔接上文内容,通过 HAVING 子句,我们筛选出所有阵营中最早的注册时间,语句如下:
mysql> select camp,MIN(register_time) as register_time from roles group by camp HAVING register_time > '2018-12-01 00:00:00';
+-------+---------------------+
| camp | register_time |
+-------+---------------------+
| horde | 2018-12-01 16:11:28 |
+-------+---------------------+
1 row in set (0.00 sec)
mysql>
说明:实际上,上述语句中 HAVING 包含的 register_time 等同于聚合函数 MIN(register_time)。where子句不能包含聚合函数,所以此处只能使用 HAVING 子句。如果使用 where 子句替换 having 子句,会报错:
mysql> select camp,MIN(register_time) as register_time from roles group by camp WHERE register_time > '2018-12-01 00:00:00';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE register_time > '2018-12-01 00:00:00'' at line 1
mysql>
【HAVING与WHERE的区别】:
- where 子句的作用:在对查询结果进行分组前,把不符合where条件的行去掉,即在分组之前过滤数据。另外,where条件中不能包含聚组函数。
- having 子句的作用:筛选满足条件的组,即在分组后过滤数据,条件中经常包含聚组函数,使用 having 条件过滤出特定的组。