mysql菜鸟教程

专栏导航

7.1 聚合函数:COUNT、SUM、AVG、MAX、MIN

      当我们需要对数据进行统计分析时——比如计算学生总数、求平均成绩、找出最高分或统计销售总额——就需要使用聚合函数。聚合函数是SQL中用于对一组值执行计算并返回单个汇总值的强大工具。

一、聚合函数的核心价值

为什么需要聚合函数?

  1. 数据汇总:从大量数据中提取有意义的统计信息

  2. 决策支持:为业务决策提供数据依据(如平均销售额、最高业绩)

  3. 性能监控:统计系统指标(如用户总数、活跃度)

  4. 报表生成:生成各种统计报表和仪表板

二、五大核心聚合函数概览

函数

功能描述

典型应用场景

COUNT()

统计行数或非NULL值的数量

统计学生总数、订单数量

SUM()

计算数值列的总和

计算销售总额、工资总和

AVG()

计算数值列的平均值

计算平均成绩、平均价格

MAX()

找出最大值

找出最高分、最新订单

MIN()

找出最小值

找出最低分、最早日期

数据准备

为了方便演示,我们创建一个scores成绩表:

-- 创建学生成绩表
CREATE TABLE scores (
    id INT PRIMARY KEY AUTO_INCREMENT,
    student_id INT NOT NULL COMMENT '学生ID',
    student_name VARCHAR(50) NOT NULL COMMENT '学生姓名',
    subject VARCHAR(50) NOT NULL COMMENT '科目',
    score DECIMAL(5,2) COMMENT '成绩(百分制)',
    exam_date DATE NOT NULL COMMENT '考试日期'
);

-- 插入示例数据
INSERT INTO scores (student_id, student_name, subject, score, exam_date) VALUES
(1, '张三', '数学', 85.5, '2024-06-15'),
(1, '张三', '英语', 92.0, '2024-06-16'),
(1, '张三', '物理', 78.5, '2024-06-17'),
(2, '李四', '数学', 90.0, '2024-06-15'),
(2, '李四', '英语', 88.5, '2024-06-16'),
(2, '李四', '物理', 95.0, '2024-06-17'),
(3, '王五', '数学', 76.0, '2024-06-15'),
(3, '王五', '英语', 81.5, '2024-06-16'),
(3, '王五', '物理', 69.0, '2024-06-17'),
(4, '赵六', '数学', 94.5, '2024-06-15'),
(4, '赵六', '英语', 96.0, '2024-06-16'),
(4, '赵六', '物理', 92.5, '2024-06-17'),
(5, '钱七', '数学', 88.0, '2024-06-15'),
(5, '钱七', '英语', NULL, '2024-06-16'),  -- 缺考,成绩为NULL
(5, '钱七', '物理', 84.5, '2024-06-17');

-- 查看数据
SELECT * FROM scores ORDER BY student_id, subject;

1. COUNT() - 计数函数

统计行数或非NULL值的数量。

基本语法

COUNT(*)            -- 统计所有行数,包括NULL值
COUNT(列名)         -- 统计指定列的非NULL值数量
COUNT(DISTINCT 列名) -- 统计指定列的不重复非NULL值数量

使用示例

-- 1. 统计总记录数(包括所有行)
SELECT COUNT(*) AS total_records FROM scores;
-- 返回:15

-- 2. 统计有成绩的学生数量(排除NULL)
SELECT COUNT(score) AS scored_students FROM scores;
-- 返回:14(钱七的英语成绩为NULL,不计数)

-- 3. 统计参加考试的不同学生数量
SELECT COUNT(DISTINCT student_id) AS distinct_students FROM scores;
-- 返回:5

-- 4. 统计有多少个不同的科目
SELECT COUNT(DISTINCT subject) AS distinct_subjects FROM scores;
-- 返回:3

2. SUM() - 求和函数

计算数值列的总和。

基本语法

SUM(列名)                    -- 计算总和
SUM(DISTINCT 列名)           -- 计算不重复值的总和

使用示例

-- 1. 计算所有成绩的总分
SELECT SUM(score) AS total_score FROM scores;
-- 返回:所有有效成绩的总和

-- 2. 计算数学科目的总分
SELECT SUM(score) AS math_total_score 
FROM scores 
WHERE subject = '数学';
-- 返回:433.5 (85.5 + 90 + 76 + 94.5 + 88)

-- 3. 计算不重复成绩的总和(意义不大,仅演示语法)
SELECT SUM(DISTINCT score) AS distinct_scores_sum 
FROM scores 
WHERE subject = '数学';
-- 返回:可能有重复分数时会有差异

3. AVG() - 平均值函数

计算数值列的平均值。

基本语法

AVG(列名)                    -- 计算平均值
AVG(DISTINCT 列名)           -- 计算不重复值的平均值

使用示例

-- 1. 计算所有成绩的平均分
SELECT AVG(score) AS average_score FROM scores;
-- 注意:NULL值不参与计算,分母是14不是15

-- 2. 计算数学科目的平均分
SELECT 
    AVG(score) AS math_avg_score,
    COUNT(score) AS math_student_count
FROM scores 
WHERE subject = '数学';
-- 返回:平均分86.7,学生数5

-- 3. 手动验证平均分计算
SELECT 
    SUM(score) AS total,
    COUNT(score) AS count,
    SUM(score) / COUNT(score) AS manual_avg
FROM scores 
WHERE subject = '数学';

4. MAX() - 最大值函数

找出指定列的最大值。

基本语法

MAX(列名)

使用示例

-- 1. 找出最高成绩
SELECT MAX(score) AS highest_score FROM scores;
-- 返回:96.0

-- 2. 找出数学科目的最高分
SELECT MAX(score) AS math_highest_score 
FROM scores 
WHERE subject = '数学';
-- 返回:94.5

-- 3. 找出最晚的考试日期
SELECT MAX(exam_date) AS latest_exam_date FROM scores;
-- 返回:2024-06-17

-- 4. 找出最长的学生姓名
SELECT MAX(LENGTH(student_name)) AS max_name_length FROM scores;

5. MIN() - 最小值函数

找出指定列的最小值。

基本语法

MIN(列名)

使用示例

-- 1. 找出最低成绩
SELECT MIN(score) AS lowest_score FROM scores;
-- 返回:69.0

-- 2. 找出英语科目的最低分
SELECT MIN(score) AS english_lowest_score 
FROM scores 
WHERE subject = '英语' AND score IS NOT NULL;
-- 返回:81.5

-- 3. 找出最早的考试日期
SELECT MIN(exam_date) AS earliest_exam_date FROM scores;
-- 返回:2024-06-15

组合使用多个聚合函数

在实际应用中,我们经常需要同时查看多个统计指标:

-- 查看所有成绩的总体统计
SELECT 
    COUNT(*) AS total_records,
    COUNT(score) AS valid_scores,
    SUM(score) AS total_score,
    AVG(score) AS average_score,
    MAX(score) AS highest_score,
    MIN(score) AS lowest_score
FROM scores;

-- 查看数学科目的详细统计
SELECT 
    subject,
    COUNT(*) AS total_tests,
    COUNT(score) AS completed_tests,
    SUM(score) AS total_score,
    AVG(score) AS average_score,
    MAX(score) AS highest_score,
    MIN(score) AS lowest_score,
    MAX(score) - MIN(score) AS score_range  -- 计算极差
FROM scores
WHERE subject = '数学';

三、重要注意事项与特殊行为

1. NULL值的处理

聚合函数在计算时自动忽略NULL值(COUNT(*)除外):

-- 注意COUNT(*)和COUNT(score)的区别
SELECT 
    COUNT(*) AS total_rows,          -- 返回15(所有行)
    COUNT(score) AS non_null_scores, -- 返回14(忽略NULL)
    AVG(score) AS average_score      -- 基于14个有效成绩计算
FROM scores;

2. 空表查询的结果

当对空表使用聚合函数时:

-- 假设查询一个不存在的条件
SELECT 
    COUNT(*) AS count_all,
    SUM(score) AS sum_score,
    AVG(score) AS avg_score,
    MAX(score) AS max_score,
    MIN(score) AS min_score
FROM scores
WHERE 1 = 0;  -- 条件永远不成立

-- 结果:
-- count_all: 0
-- sum_score: NULL
-- avg_score: NULL
-- max_score: NULL
-- min_score: NULL

3. 数据类型限制

  • SUM()AVG()只适用于数值类型(INT、DECIMAL等)

  • MAX()MIN()适用于数值、日期、字符串等可比较的类型

  • COUNT()适用于任何类型

四、聚合函数与GROUP BY结合

聚合函数最强大的功能是与GROUP BY子句结合,进行分组统计(这将在下一节详细介绍,此处先做简要介绍):

-- 按科目分组统计
SELECT 
    subject,
    COUNT(*) AS student_count,
    AVG(score) AS average_score,
    MAX(score) AS highest_score,
    MIN(score) AS lowest_score
FROM scores
WHERE score IS NOT NULL
GROUP BY subject
ORDER BY average_score DESC;

-- 按学生分组统计
SELECT 
    student_id,
    student_name,
    COUNT(*) AS exam_count,
    AVG(score) AS average_score,
    SUM(score) AS total_score
FROM scores
WHERE score IS NOT NULL
GROUP BY student_id, student_name
ORDER BY average_score DESC;

五、实用技巧与常见问题

1. 保留小数位数

-- 使用ROUND函数控制小数位数
SELECT 
    subject,
    ROUND(AVG(score), 1) AS avg_score_1decimal,
    ROUND(AVG(score), 2) AS avg_score_2decimal
FROM scores
WHERE score IS NOT NULL
GROUP BY subject;

2. 处理除零错误

-- 安全计算百分比(避免COUNT(*)为0时出错)
SELECT 
    subject,
    COUNT(score) AS completed,
    COUNT(*) AS total,
    CASE 
        WHEN COUNT(*) > 0 THEN 
            ROUND(COUNT(score) * 100.0 / COUNT(*), 2)
        ELSE 0
    END AS completion_rate_percent
FROM scores
GROUP BY subject;

3. 性能优化建议

  • 对经常用于聚合的列建立索引

  • 在大数据表上,考虑使用采样统计或预计算

  • 避免在WHERE条件中对聚合结果进行筛选(应使用HAVING)

六、练习与解答

练习题目

基于scores表,请编写SQL语句实现以下需求:

  1. 基础统计:统计总共有多少个有效的成绩记录

  2. 科目分析:计算每个科目的平均分、最高分和最低分

  3. 学生分析:计算每个学生的总成绩和平均成绩

  4. 数据质量:统计每个学生的缺考科目数量(成绩为NULL)

  5. 综合应用:找出平均分最高的科目和学生

  6. 挑战题:计算每个科目的成绩标准差(使用STDDEV或手动计算)

参考答案

-- 1. 统计总共有多少个有效的成绩记录
SELECT COUNT(score) AS valid_score_count FROM scores;

-- 2. 计算每个科目的平均分、最高分和最低分
SELECT 
    subject,
    COUNT(score) AS student_count,
    ROUND(AVG(score), 2) AS average_score,
    MAX(score) AS highest_score,
    MIN(score) AS lowest_score
FROM scores
GROUP BY subject
ORDER BY average_score DESC;

-- 3. 计算每个学生的总成绩和平均成绩
SELECT 
    student_id,
    student_name,
    COUNT(score) AS exam_count,
    SUM(score) AS total_score,
    ROUND(AVG(score), 2) AS average_score
FROM scores
GROUP BY student_id, student_name
ORDER BY average_score DESC;

-- 4. 统计每个学生的缺考科目数量
SELECT 
    student_id,
    student_name,
    COUNT(*) - COUNT(score) AS missing_exams
FROM scores
GROUP BY student_id, student_name
HAVING missing_exams > 0;

-- 5. 找出平均分最高的科目和学生
-- 最高平均分的科目
SELECT subject, ROUND(AVG(score), 2) AS avg_score
FROM scores
WHERE score IS NOT NULL
GROUP BY subject
ORDER BY avg_score DESC
LIMIT 1;

-- 最高平均分的学生
SELECT student_name, ROUND(AVG(score), 2) AS avg_score
FROM scores
WHERE score IS NOT NULL
GROUP BY student_name
ORDER BY avg_score DESC
LIMIT 1;

-- 6. 计算每个科目的成绩标准差
SELECT 
    subject,
    COUNT(score) AS count,
    ROUND(AVG(score), 2) AS average,
    ROUND(STDDEV(score), 2) AS std_deviation  -- MySQL中使用STD或STDDEV
FROM scores
WHERE score IS NOT NULL
GROUP BY subject;

七、聚合函数要点总结

函数特性对比表

函数

是否忽略NULL

适用数据类型

空表返回值

典型用途

COUNT()

COUNT(*)否,COUNT(列)是

任意

0

统计数量

SUM()

数值型

NULL

计算总和

AVG()

数值型

NULL

计算平均值

MAX()

可比较类型

NULL

找出最大值

MIN()

可比较类型

NULL

找出最小值

使用注意事项总结

  1. NULL处理:几乎所有聚合函数都自动忽略NULL值(COUNT(*)除外)

  2. 数据类型:确保函数与数据类型匹配(如对字符串使用SUM()会报错)

  3. 性能考虑:大数据表上使用聚合函数可能较慢,考虑添加索引

  4. 分组使用:聚合函数通常与GROUP BY结合进行分组统计

  5. 结果精度:使用ROUND()控制小数位数,提高结果可读性

最佳实践建议

  1. 先验证数据质量:使用COUNT()检查NULL值和数据完整性

  2. 组合使用函数:同时查看多个统计指标以获得全面了解

  3. 添加条件过滤:使用WHERE在聚合前过滤不需要的数据

  4. 使用别名:为聚合结果列起有意义的别名

  5. 测试边界情况:测试空数据集、全NULL数据集等边界情况

聚合函数是SQL数据分析的基石,掌握它们能让你从"查看数据"升级到"理解数据"。记住核心原则:聚合函数将多行数据汇总为有意义的单个统计值


发表评论

昵称:
联系方式:
评论内容:

所有评论

关于我 备案号:蜀ICP备2023042032号-1