SQL:聚合函数(Aggregate Functions)
目录
第一性原理出发思考 ——我们为什么需要聚合函数?
什么是聚合函数?
常见聚合函数 + 实例讲解
🔸 1. COUNT() —— 计数
🔸 2. MAX() / MIN() —— 最大 / 最小值
🔸 3. SUM() —— 求和
🔸 4. AVG() —— 平均值
GROUP BY
GROUP BY 是什么?
执行逻辑
GROUP BY 的重要规则
HAVING
为什么还要 HAVING?
HAVING 是什么?
实例讲解
HAVING 和 WHERE 的区别
思维图:GROUP BY + HAVING 工作流程
第一性原理出发思考 ——我们为什么需要聚合函数?
在数据库中,查询的本质是从一堆数据中“找出我们需要的信息”。有时候我们不仅想看到“每一行”,而是想对一整列进行“汇总”,比如:
-
一共预订了多少场电影?
-
哪个用户最爱看电影?
-
每部电影平均有多少人观看?
这个时候,我们就需要——聚合函数。
什么是聚合函数?
聚合函数是 MySQL 中用于对一整列的数据进行统计、计算或汇总的函数。它不是作用于“某一行”,而是作用于“一列”或“一组”数据。
常见聚合函数 + 实例讲解
我们来建一个简单的工资表 employees,字段如下:
CREATE TABLE employees (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50),salary INT
);
插入一些数据:
INSERT INTO employees (name, salary) VALUES
('Alice', 5000),
('Bob', 6000),
('Charlie', 5500),
('Diana', 7000),
('Eve', 6500),
('Frank', 5200);
🔸 1. COUNT()
—— 计数
SELECT COUNT(*) FROM employees;
我们给数据库一个表,它扫描所有行,每遇到一行就 +1
,最后告诉你一共有几行数据。
最后返回 6
SELECT COUNT(salary) FROM employees;
与 COUNT(*)
类似,但如果有 NULL
工资的员工,不计入。
🔸 2. MAX()
/ MIN()
—— 最大 / 最小值
SELECT MAX(salary), MIN(salary) FROM employees;
数据库扫描每一个值,记录当前最大/最小值,直到最后一行。
最后返回:MAX: 7000, MIN: 5000
🔸 3. SUM()
—— 求和
SELECT SUM(salary) FROM employees;
我们把这一列的值都加起来,输出总和。适合处理“总销售额”、“总时长”等问题。
最后返回:5000 + 6000 + 5500 + 7000 + 6500 + 5200 = 35,200
🔸 4. AVG()
—— 平均值
SELECT AVG(salary) FROM employees;
就是 SUM(salary) / COUNT(salary)
,把总量除以人数,得到“人均”指标。
最后返回:35200 / 6 = 5866.67
你还可以这样玩:
-- 所有工资加 500 后的平均值是多少?
SELECT AVG(salary + 500) FROM employees;-- 平均名字长度(字符串函数 + 聚合函数)
SELECT AVG(CHAR_LENGTH(name)) FROM employees;
GROUP BY
我们之前讲的聚合函数是对“一整列”做统计,但很多时候,我们想知道:
各个部门的平均工资分别是多少?
这就需要把“整张表”按部门拆成若干小组,每一组内部再用聚合函数统计。
💡 这时候,我们就需要 GROUP BY
。
GROUP BY 是什么?
GROUP BY
是 SQL 中的“分组器”
它把一张大表,按某个字段(或字段组合)划分成一组组数据,然后对每组单独使用聚合函数。
执行逻辑
SELECT A, 聚合函数(B)
FROM 表
GROUP BY A;
你在做的是:
-
把表 按 A 的值分组
-
每一组内部,对 B 进行聚合运算
-
然后输出每一组的 A + 对应的聚合结果
🎯 目标:统计各个部门的平均工资
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department;
这条 SQL 的背后逻辑是这样的:
-
扫描整张表
-
按
department
字段的值,把表划分为若干组:-
HR: [Alice, Charlie, Frank]
-
IT: [Bob, Diana]
-
Finance: [Eve]
-
-
对每组单独执行
AVG(salary)
-
输出每组的
department
和对应的avg_salary
执行结果:
department | avg_salary |
---|---|
HR | 5233.33 |
IT | 6500.00 |
Finance | 6500.00 |
GROUP BY 的重要规则
规则 | 说明 |
---|---|
SELECT 中非聚合字段必须出现在 GROUP BY 中 | 除非是聚合函数计算的,否则 SELECT 中的字段必须被 GROUP BY |
GROUP BY 后面可以接多个字段 | 表示按多个维度进行分组 |
所以 只要出现在 SELECT 中的字段,不是用聚合函数包裹的,就必须是分组的依据,也就是 GROUP BY
中出现的字段。
整张表 → 按字段值分组 → 每组做聚合 → 输出每组统计结果
HAVING
为什么还要 HAVING
?
我们已经知道:每个部门的平均工资。但问题来了:
❓“只想要平均工资大于 6000 的部门”怎么办?
你可能第一反应是:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 6000 -- 🚫 错误用法
GROUP BY department;
❌ 错误!
因为 WHERE
是在分组之前起作用的,根本没法识别 AVG(salary)
这种“分组后的值”。
HAVING 是什么?
HAVING
是用来 过滤分组后的结果 的
它和 WHERE
类似,但发生在 GROUP BY
之后
实例讲解
🎯 问题:找出平均工资高于 6000 的部门
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 6000;
🔍 数据回顾(之前的平均工资):
department | avg_salary |
---|---|
HR | 5233.33 |
IT | 6500.00 |
Finance | 6500.00 |
📌 这条 SQL 会返回:
department | avg_salary |
---|---|
IT | 6500.00 |
Finance | 6500.00 |
因为只有这两个部门的平均工资大于 6000。
🔹 统计每个部门人数大于 2 的部门:
SELECT department, COUNT(*) AS num_employees
FROM employees
GROUP BY department
HAVING COUNT(*) > 2;
🔹 平均工资等于最大工资的部门
SELECT department, AVG(salary), MAX(salary) FROM employees
GROUP BY department
HAVING AVG(salary) = MAX(salary);
使用别名:
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING avg_salary > 6000; -- ✅ 正确用法
HAVING 和 WHERE 的区别
语句部分 | 用途 | 作用顺序(谁先执行) |
---|---|---|
WHERE | 筛选原始数据 | 在分组之前执行 |
HAVING | 筛选分组结果 | 在分组之后执行 |
WHERE 是筛选行,HAVING 是筛选组。
WHERE 是先手,HAVING 是后手。
思维图:GROUP BY + HAVING 工作流程
原始表↓ (WHERE)
过滤掉不满足条件的行↓ (GROUP BY)
按照字段分组↓ (聚合函数)
计算每组的结果↓ (HAVING)
筛选掉不满足条件的组↓ (SELECT)
最终展示结果