Skip to content

第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;

查询结果:

学生人数总成绩平均成绩最高分最低分
50425085.009862

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人数
120
218
312
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_idgender人数
112
18
210
28
36
36

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;

查询结果:

班级人数平均分最高分最低分
12086.59872
21884.29568
31282.89262

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人数
120
218

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 BYGROUP BY 字段分组统计
HAVINGHAVING 条件筛选分组结果

关键区别:

  • WHERE:对原始数据筛选(分组前)
  • HAVING:对分组结果筛选(分组后)

8.8 课后练习

  1. 统计学生总人数
  2. 统计男生的平均成绩
  3. 按班级分组,统计各班人数和平均成绩
  4. 查询人数超过10人的班级
  5. 查询平均成绩最高的班级

参考答案:

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)
  • 子查询
  • 索引优化
  • 事务处理
  • 实战项目案例

敬请期待!

© 2026 编程马·菜鸟教程 版权所有