Appearance
第8章:聚合函数与分组查询(进阶查询)
本章介绍如何使用聚合函数进行数据统计,以及如何通过分组查询实现数据汇总分析。这些技能在制作数据报表、统计分析时非常重要。
8.1 常用聚合函数(核心,数据统计)
聚合函数用于对一组值进行计算,返回单个值。常用于数据统计分析。
8.1.1 COUNT() - 统计记录数
统计记录条数,最常用:
sql
-- 统计学生总数
SELECT COUNT(*) FROM students;
-- 统计有邮箱的学生数量(email不为NULL)
SELECT COUNT(email) FROM students;
-- 统计1班的学生数量
SELECT COUNT(*) FROM students WHERE class_id = 1;COUNT() 的几种用法:
| 用法 | 说明 | 示例 |
|---|---|---|
COUNT(*) | 统计所有记录(包括NULL) | SELECT COUNT(*) FROM students; |
COUNT(字段) | 统计该字段非NULL的记录 | SELECT COUNT(email) FROM students; |
COUNT(DISTINCT 字段) | 统计去重后的记录数 | SELECT COUNT(DISTINCT class_id) FROM students; |
sql
-- 统计有多少个不同的班级
SELECT COUNT(DISTINCT class_id) FROM students;
-- 统计有多少个不同的性别
SELECT COUNT(DISTINCT gender) FROM students;8.1.2 SUM() - 求和
计算某列的总和:
sql
-- 计算所有学生的总成绩
SELECT SUM(score) FROM students;
-- 计算1班学生的总成绩
SELECT SUM(score) FROM students WHERE class_id = 1;
-- 计算所有学生的年龄总和
SELECT SUM(age) FROM students;注意
SUM() 只能用于数值类型字段!
8.1.3 AVG() - 求平均值
计算某列的平均值:
sql
-- 计算学生的平均成绩
SELECT AVG(score) FROM students;
-- 计算1班学生的平均成绩
SELECT AVG(score) FROM students WHERE class_id = 1;
-- 计算学生的平均年龄
SELECT AVG(age) FROM students;保留小数位数:
sql
-- 平均成绩保留2位小数
SELECT ROUND(AVG(score), 2) FROM students;
-- 或使用 FORMAT(格式化为字符串)
SELECT FORMAT(AVG(score), 2) FROM students;8.1.4 MAX() - 求最大值
获取某列的最大值:
sql
-- 查询最高成绩
SELECT MAX(score) FROM students;
-- 查询最大年龄
SELECT MAX(age) FROM students;
-- 查询1班的最高成绩
SELECT MAX(score) FROM students WHERE class_id = 1;8.1.5 MIN() - 求最小值
获取某列的最小值:
sql
-- 查询最低成绩
SELECT MIN(score) FROM students;
-- 查询最小年龄
SELECT MIN(age) FROM students;
-- 查询2班的最低成绩
SELECT MIN(score) FROM students WHERE class_id = 2;8.1.6 聚合函数组合使用
多个聚合函数可以同时使用:
sql
-- 统计学生人数、总成绩、平均成绩、最高分和最低分
SELECT
COUNT(*) AS 学生人数,
SUM(score) AS 总成绩,
AVG(score) AS 平均成绩,
MAX(score) AS 最高分,
MIN(score) AS 最低分
FROM students;查询结果:
| 学生人数 | 总成绩 | 平均成绩 | 最高分 | 最低分 |
|---|---|---|---|---|
| 50 | 4250 | 85.00 | 98 | 62 |
8.2 分组查询(GROUP BY,核心)
使用 GROUP BY 将数据按指定字段分组,然后对每组数据进行统计。
8.2.1 基本语法
sql
SELECT 分组字段, 聚合函数 FROM 表名 GROUP BY 分组字段;8.2.2 按单字段分组
sql
-- 按班级分组,统计每个班的学生人数
SELECT class_id, COUNT(*) AS 人数
FROM students
GROUP BY class_id;查询结果:
| class_id | 人数 |
|---|---|
| 1 | 20 |
| 2 | 18 |
| 3 | 12 |
sql
-- 按性别分组,统计男女生人数
SELECT gender, COUNT(*) AS 人数
FROM students
GROUP BY gender;查询结果:
| gender | 人数 |
|---|---|
| 男 | 28 |
| 女 | 22 |
8.2.3 多字段分组
按多个字段组合分组:
sql
-- 按班级和性别分组,统计各班男女生人数
SELECT class_id, gender, COUNT(*) AS 人数
FROM students
GROUP BY class_id, gender;查询结果:
| class_id | gender | 人数 |
|---|---|---|
| 1 | 男 | 12 |
| 1 | 女 | 8 |
| 2 | 男 | 10 |
| 2 | 女 | 8 |
| 3 | 男 | 6 |
| 3 | 女 | 6 |
8.2.4 分组+多聚合函数
sql
-- 按班级分组,统计各班人数、平均成绩、最高分和最低分
SELECT
class_id AS 班级,
COUNT(*) AS 人数,
AVG(score) AS 平均分,
MAX(score) AS 最高分,
MIN(score) AS 最低分
FROM students
GROUP BY class_id;查询结果:
| 班级 | 人数 | 平均分 | 最高分 | 最低分 |
|---|---|---|---|---|
| 1 | 20 | 86.5 | 98 | 72 |
| 2 | 18 | 84.2 | 95 | 68 |
| 3 | 12 | 82.8 | 92 | 62 |
8.3 分组筛选(HAVING)
HAVING 用于对分组后的结果进行筛选,与 WHERE 的区别在于:
| 关键字 | 作用时机 | 作用对象 | 能否使用聚合函数 |
|---|---|---|---|
| WHERE | 分组前 | 原始数据行 | 否 |
| HAVING | 分组后 | 分组后的结果 | 是 |
8.3.1 HAVING 基本用法
sql
-- 查询人数超过15人的班级
SELECT class_id, COUNT(*) AS 人数
FROM students
GROUP BY class_id
HAVING COUNT(*) > 15;查询结果:
| class_id | 人数 |
|---|---|
| 1 | 20 |
| 2 | 18 |
8.3.2 WHERE 与 HAVING 的区别
sql
-- WHERE:筛选原始数据(分组前)
-- 查询1班和2班的学生,按班级分组统计
SELECT class_id, COUNT(*) AS 人数
FROM students
WHERE class_id IN (1, 2) -- 先筛选1班和2班
GROUP BY class_id;
-- HAVING:筛选分组结果(分组后)
-- 查询所有班级,只显示人数超过15人的班级
SELECT class_id, COUNT(*) AS 人数
FROM students
GROUP BY class_id
HAVING COUNT(*) > 15; -- 再筛选人数>15的8.3.3 WHERE 和 HAVING 同时使用
sql
-- 查询1班和2班中,平均成绩超过85分的班级
SELECT
class_id,
COUNT(*) AS 人数,
AVG(score) AS 平均分
FROM students
WHERE class_id IN (1, 2) -- 先筛选班级
GROUP BY class_id
HAVING AVG(score) > 85; -- 再筛选平均分>85的8.3.4 常见使用场景
sql
-- 查询平均成绩超过85分的班级
SELECT class_id, AVG(score) AS 平均分
FROM students
GROUP BY class_id
HAVING AVG(score) > 85;
-- 查询人数在10到20之间的班级
SELECT class_id, COUNT(*) AS 人数
FROM students
GROUP BY class_id
HAVING COUNT(*) BETWEEN 10 AND 20;
-- 查询最高分超过90分的班级
SELECT class_id, MAX(score) AS 最高分
FROM students
GROUP BY class_id
HAVING MAX(score) > 90;8.4 综合实操案例
案例1:班级成绩统计报表
sql
-- 生成班级成绩统计报表
SELECT
class_id AS 班级,
COUNT(*) AS 总人数,
AVG(score) AS 平均分,
MAX(score) AS 最高分,
MIN(score) AS 最低分,
SUM(CASE WHEN score >= 60 THEN 1 ELSE 0 END) AS 及格人数,
ROUND(SUM(CASE WHEN score >= 60 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS 及格率
FROM students
GROUP BY class_id
ORDER BY 平均分 DESC;案例2:按性别统计成绩
sql
-- 统计男女生的成绩情况
SELECT
gender AS 性别,
COUNT(*) AS 人数,
AVG(score) AS 平均分,
MAX(score) AS 最高分,
MIN(score) AS 最低分
FROM students
GROUP BY gender;案例3:筛选优秀班级
sql
-- 查询平均成绩超过85分且人数超过15人的班级
SELECT
class_id,
COUNT(*) AS 人数,
AVG(score) AS 平均分
FROM students
GROUP BY class_id
HAVING AVG(score) > 85 AND COUNT(*) > 15;案例4:多维度统计
sql
-- 按班级和性别统计人数和平均分
SELECT
class_id AS 班级,
gender AS 性别,
COUNT(*) AS 人数,
ROUND(AVG(score), 2) AS 平均分
FROM students
GROUP BY class_id, gender
ORDER BY class_id, gender;8.5 新手易错点
❌ 错误1:聚合函数与普通字段混用
sql
-- 错误:SELECT 中同时出现普通字段和聚合函数,但普通字段未在 GROUP BY 中
SELECT name, COUNT(*) FROM students;
-- 报错:name 必须出现在 GROUP BY 子句中
-- 正确:普通字段必须在 GROUP BY 中
SELECT class_id, COUNT(*) FROM students GROUP BY class_id;
-- 正确:只使用聚合函数
SELECT COUNT(*) FROM students;规则
当 SELECT 中同时有普通字段和聚合函数时,普通字段必须出现在 GROUP BY 子句中!
❌ 错误2:WHERE 中使用聚合函数
sql
-- 错误:WHERE 中不能使用聚合函数
SELECT class_id, COUNT(*) FROM students WHERE COUNT(*) > 10 GROUP BY class_id;
-- 正确:使用 HAVING
SELECT class_id, COUNT(*) FROM students GROUP BY class_id HAVING COUNT(*) > 10;❌ 错误3:GROUP BY 与 WHERE 使用顺序错误
sql
-- 错误顺序
SELECT class_id, COUNT(*) FROM students
GROUP BY class_id
WHERE class_id IN (1, 2);
-- 正确顺序
SELECT class_id, COUNT(*) FROM students
WHERE class_id IN (1, 2)
GROUP BY class_id;❌ 错误4:HAVING 位置错误
sql
-- 错误:HAVING 必须在 GROUP BY 之后
SELECT class_id, COUNT(*) FROM students
HAVING COUNT(*) > 10
GROUP BY class_id;
-- 正确顺序
SELECT class_id, COUNT(*) FROM students
GROUP BY class_id
HAVING COUNT(*) > 10;8.6 SQL 语句完整执行顺序
sql
SELECT 字段列表 -- 5. 选择字段
FROM 表名 -- 1. 确定数据来源
WHERE 条件 -- 2. 筛选原始数据
GROUP BY 分组字段 -- 3. 分组
HAVING 分组筛选条件 -- 4. 筛选分组结果
ORDER BY 排序字段 -- 6. 排序
LIMIT 起始, 数量; -- 7. 限制返回数量记忆口诀:
从(FROM)哪张表,按(WHERE)什么条件,分(GROUP BY)什么组,过(HAVING)什么筛,选(SELECT)什么字段,排(ORDER BY)什么序,限(LIMIT)多少条。
8.7 本章小结
| 知识点 | 语法 | 用途 |
|---|---|---|
| COUNT() | COUNT(*) | 统计记录数 |
| SUM() | SUM(字段) | 求和 |
| AVG() | AVG(字段) | 求平均值 |
| MAX() | MAX(字段) | 求最大值 |
| MIN() | MIN(字段) | 求最小值 |
| GROUP BY | GROUP BY 字段 | 分组统计 |
| HAVING | HAVING 条件 | 筛选分组结果 |
关键区别:
WHERE:对原始数据筛选(分组前)HAVING:对分组结果筛选(分组后)
8.8 课后练习
- 统计学生总人数
- 统计男生的平均成绩
- 按班级分组,统计各班人数和平均成绩
- 查询人数超过10人的班级
- 查询平均成绩最高的班级
参考答案:
sql
-- 练习1
SELECT COUNT(*) FROM students;
-- 练习2
SELECT AVG(score) FROM students WHERE gender = '男';
-- 练习3
SELECT class_id, COUNT(*), AVG(score)
FROM students
GROUP BY class_id;
-- 练习4
SELECT class_id, COUNT(*)
FROM students
GROUP BY class_id
HAVING COUNT(*) > 10;
-- 练习5
SELECT class_id, AVG(score) AS avg_score
FROM students
GROUP BY class_id
ORDER BY avg_score DESC
LIMIT 1;8.9 下章预告
下一部分将进入 MySQL 进阶操作与实战应用,包括:
- 多表查询与连接(JOIN)
- 子查询
- 索引优化
- 事务处理
- 实战项目案例
敬请期待!
