MySQL GROUP BY 和 HAVING 子句示例
⚡ 智能摘要
SQL 的 GROUP BY 和 HAVING 子句可以将详细行转换为汇总报告。GROUP BY 将具有相同值的行合并为一个组,每组一行;而 HAVING 在应用 COUNT 等聚合函数后,对这些组进行筛选。

什么是 SQL GROUP BY 子句?
GROUP BY 子句是一个 SQL 命令,用于 将具有相同值的行分组它写在 SELECT 语句中,通常与聚合函数一起使用,以从数据库中生成汇总报告。
它的作用就是这样:它 汇总数据 存储在数据库中。包含 GROUP BY 子句的查询称为分组查询,它们为每个分组项返回一行。
SQL GROUP BY 语法
既然该子句的用途已经明确,让我们来看看基本分组查询的语法。
SELECT statements... GROUP BY column_name1[, column_name2, ...] [HAVING condition];
点击这里
- “SELECT 语句…是标准 SQL SELECT 命令查询。
- “通过...分组 列名1”是执行组操作的条款ping 基于 column_name1。
- “[, column_name2, …]“ ”是可选的,当组为 时表示其他列名ping 在多列上进行操作。
- “[患有某种疾病]“ ”是可选的,用于限制受 GROUP BY 子句影响的行。它类似于 WHERE 子句只是它是在组之后应用的。ping.
的Grouping 使用单列
要快速了解 SQL GROUP BY 子句的效果,最好的方法是比较未分组查询和分组查询。首先,编写一个简单的查询,返回 members 表中所有性别条目。
SELECT `gender` FROM `members`;
| 性别 |
|---|
| (女) |
| (女) |
| (男) |
| (女) |
| (男) |
| (男) |
| (男) |
| (男) |
| (男) |
返回九行结果,且每个值都重复出现。假设我们想要获取性别的唯一值。以下查询添加了 GROUP BY 子句。
SELECT `gender` FROM `members` GROUP BY `gender`;
在以下位置执行上述脚本 MySQL 工作台 针对 myflixdb 我们得到以下结果。
| 性别 |
|---|
| (女) |
| (男) |
请注意,由于表中仅包含两种性别类型,因此只返回了两行数据。GROUP BY 子句将所有“男性”成员分组在一起,并返回一行数据;对“女性”成员也执行了相同的操作。
的Grouping 使用多列
的Grouping 单列数据对于实际报表来说通常过于粗略。GROUP BY 子句接受以逗号分隔的列列表,每个分组由这些列的值组合而成。
假设我们想要一个电影类别 ID 值及其对应的电影上映年份列表。首先观察一下这个简单查询的输出结果。
SELECT `category_id`, `year_released` FROM `movies`;
| 类别编号 | 发行年份 |
|---|---|
| 1 | 2011 |
| 2 | 2008 |
| 无 | 2008 |
| 无 | 2010 |
| 8 | 2007 |
| 6 | 2007 |
| 6 | 2007 |
| 8 | 2005 |
| 无 | 2012 |
| 7 | 1920 |
| 8 | 无 |
| 8 | 1920 |
高亮显示的行表明结果中包含重复项。使用 GROUP BY 子句执行相同的查询即可删除这些重复项。
SELECT `category_id`, `year_released` FROM `movies` GROUP BY `category_id`, `year_released`;
在以下位置执行上述脚本 MySQL 使用 Workbench 对 myflixdb 进行测试,我们得到了如下所示的结果。
| 类别编号 | 发行年份 |
|---|---|
| 无 | 2008 |
| 无 | 2010 |
| 无 | 2012 |
| 1 | 2011 |
| 2 | 2008 |
| 6 | 2007 |
| 7 | 1920 |
| 8 | 1920 |
| 8 | 2005 |
| 8 | 2007 |
GROUP BY 子句同时作用于 category_id 和 year_released 来识别 独特的 行。2007 年第 6 类的两行重复数据合并为一行。
经验法则: 如果类别 ID 相同但发布年份不同,则该行被视为唯一记录。如果多行的类别 ID 和发布年份相同,则这些行被视为重复记录,仅显示其中一条。
的Grouping 和聚合函数
删除重复项很有用,但群组的真正力量在于ping 当它与……配对时出现 聚合函数聚合函数为每个组计算一个值:COUNT 函数计算行数,SUM 函数将值相加, AVGMIN 和 MAX 描述了价差。
假设我们想要获取数据库中男性和女性成员的总数。下面的脚本可以实现这一点。
SELECT `gender`, COUNT(`membership_number`) FROM `members` GROUP BY `gender`;
在以下位置执行上述脚本 MySQL 使用 Workbench 对 myflixdb 数据库进行测试,得到以下结果。
| 性别 | COUNT(`membership_number`) |
|---|---|
| (女) | 3 |
| (男) | 6 |
这些行按唯一的性别值分组,每个组内的行数由 COUNT 聚合函数统计。九条成员记录合并为两行汇总数据。
使用 HAVING 子句限制查询结果
的Grouping并非表格中的每一行都需要包含特定条件。有时,报表必须符合特定条件,而这正是 HAVING 子句的作用。
假设我们想知道电影类别 ID 为 8 的所有上映年份。下面的脚本可以实现这一结果。
SELECT * FROM `movies` GROUP BY `category_id`, `year_released` HAVING `category_id` = 8;
在以下位置执行上述脚本 MySQL 使用 Workbench 对 myflixdb 进行测试,我们得到了如下所示的结果。
| 电影 ID | 标题 | 导向器 | 发行年份 | 类别编号 |
|---|---|---|---|---|
| 9 | Honey moonERS | 约翰舒尔茨 | 2005 | 8 |
| 5 | 爸爸的小女孩 | 无 | 2007 | 8 |
根据 HAVING 条件,只有类别 ID 为 8 的电影才被保留。
警告: MySQL 5.7 及更高版本默认启用 ONLY_FULL_GROUP_BY 模式,在该模式下,带有 GROUP BY 子句的 SELECT * 查询将被拒绝,因为 movie_id、title 和 director 既没有分组也没有聚合。在生产环境中,请显式命名分组列,例如: SELECT category_id, year_released FROM movies GROUP BY category_id, year_released HAVING category_id = 8;
WHERE、HAVING、GROUP BY 和 ORDER BY 是不同的组合。
初学者经常混淆这四个子句,因为它们都会影响结果集。区别在于…… ,尤其是 MySQL 它们依次执行:WHERE 在行分组之前执行,HAVING 在行分组之后执行,ORDER BY 最后执行。
| 条款 | 它做什么 | 运行时 | 接受聚合函数 |
|---|---|---|---|
| NeoCity | 在进行任何分组之前,先筛选单个行。ping. | 在 GROUP BY 之前 | 没有 |
| 通过...分组 | 将具有相同值的行合并为每组的一行。 | 在 WHERE 之后 | 不适用 |
| HAVING | 筛选由 GROUP BY 生成的分组。 | 在 GROUP BY 之后 | 是的,例如 HAVING COUNT(*) > 2 |
| ORDER BY | 对经过前面几个子句处理后的行进行排序。 | 姓氏 | 是的,聚合别名可以排序。 |
实际后果是性能问题。使用 WHERE 进行过滤会删除组之前的行。ping 工作开始了,因此不依赖于聚合结果的条件应该放在 WHERE 而不是 HAVING 中。
