SQL 中聚合函数 SELECT 语句的执行步骤
这个问题非常核心!理解聚合函数的执行顺序,是掌握 SQL 查询的关键。
一、核心概念:聚合函数是对"组"进行计算
聚合函数 | 作用 | 输入 | 输出 |
COUNT() | 计数 | 多行 | 一个数字 |
SUM() | 求和 | 多行 | 一个数字 |
AVG() | 平均值 | 多行 | 一个数字 |
MAX() | 最大值 | 多行 | 一个数字 |
MIN() | 最小值 | 多行 | 一个数字 |
关键点:聚合函数把多行数据"聚"成一个结果。
二、执行步骤详解
完整语法
sql
SELECT 聚合函数(列名), ...FROM 表名[WHERE 条件][GROUP BY 分组列][HAVING 分组后条件][ORDER BY 排序列];
执行顺序(非常重要!)
text
1. FROM → 确定数据来源(哪张表) ↓ 2. WHERE → 筛选行(过滤原始数据) ↓ 3. GROUP BY → 分组(把数据分成若干组) ↓ 4. 聚合函数 → 对每组进行计算 ↓ 5. HAVING → 筛选分组(过滤聚合后的结果) ↓ 6. SELECT → 选择要显示的列 ↓ 7. ORDER BY → 排序
三、场景一:对整个表进行聚合(无 GROUP BY)
示例
sql
SELECT COUNT(*) AS 总行数, SUM(price) AS 总金额, AVG(price) AS 平均价格FROM products;
执行步骤
text
步骤1:FROM products ┌─────────────────────────────────────────────┐ │ 读取 products 表的所有行 │ │ ┌─────┬──────────┬───────┐ │ │ │ id │ name │ price │ │ │ ├─────┼──────────┼───────┤ │ │ │ 1 │ 手机 │ 2999 │ │ │ │ 2 │ 电脑 │ 5999 │ │ │ │ 3 │ 耳机 │ 199 │ │ │ │ 4 │ 键盘 │ 399 │ │ │ └─────┴──────────┴───────┘ │ └─────────────────────────────────────────────┘ ↓ 步骤2:WHERE(无,跳过) ↓ 步骤3:GROUP BY(无,整张表视为一组) ↓ 步骤4:聚合函数计算 ┌─────────────────────────────────────────────┐ │ COUNT(*) = 4 │ │ SUM(price) = 2999+5999+199+399 = 9596 │ │ AVG(price) = 9596 / 4 = 2399 │ └─────────────────────────────────────────────┘ ↓ 步骤5:HAVING(无,跳过) ↓ 步骤6:SELECT(显示结果) ┌────────────┬────────────┬────────────┐ │ 总行数 │ 总金额 │ 平均价格 │ ├────────────┼────────────┼────────────┤ │ 4 │ 9596 │ 2399 │ └────────────┴────────────┴────────────┘
四、场景二:分组聚合(有 GROUP BY)
示例
sql
SELECT category, COUNT(*) AS 商品数量, SUM(price) AS 分类总金额, AVG(price) AS 分类平均价FROM productsWHERE price > 100GROUP BY categoryORDER BY 分类总金额 DESC;
执行步骤
text
步骤1:FROM products ┌─────────────────────────────────────────────────────────┐ │ 读取 products 表 │ │ ┌─────┬──────────┬───────┬──────────┐ │ │ │ id │ name │ price │ category │ │ │ ├─────┼──────────┼───────┼──────────┤ │ │ │ 1 │ 手机 │ 2999 │ 数码 │ │ │ │ 2 │ 电脑 │ 5999 │ 数码 │ │ │ │ 3 │ 耳机 │ 199 │ 数码 │ │ │ │ 4 │ 键盘 │ 399 │ 外设 │ │ │ │ 5 │ 鼠标 │ 89 │ 外设 │ │ │ └─────┴──────────┴───────┴──────────┘ │ └─────────────────────────────────────────────────────────┘ ↓ 步骤2:WHERE price > 100 ┌─────────────────────────────────────────────────────────┐ │ 筛选后:过滤掉 price <= 100 的行(鼠标 89元被过滤) │ │ ┌─────┬──────────┬───────┬──────────┐ │ │ │ id │ name │ price │ category │ │ │ ├─────┼──────────┼───────┼──────────┤ │ │ │ 1 │ 手机 │ 2999 │ 数码 │ │ │ │ 2 │ 电脑 │ 5999 │ 数码 │ │ │ │ 3 │ 耳机 │ 199 │ 数码 │ │ │ │ 4 │ 键盘 │ 399 │ 外设 │ │ │ └─────┴──────────┴───────┴──────────┘ │ └─────────────────────────────────────────────────────────┘ ↓ 步骤3:GROUP BY category ┌─────────────────────────────────────────────────────────┐ │ 分组:数码 和 外设 │ │ │ │ 组1 - 数码: │ │ ┌─────┬──────────┬───────┐ │ │ │ id │ name │ price │ │ │ ├─────┼──────────┼───────┤ │ │ │ 1 │ 手机 │ 2999 │ │ │ │ 2 │ 电脑 │ 5999 │ │ │ │ 3 │ 耳机 │ 199 │ │ │ └─────┴──────────┴───────┘ │ │ │ │ 组2 - 外设: │ │ ┌─────┬──────────┬───────┐ │ │ │ id │ name │ price │ │ │ ├─────┼──────────┼───────┤ │ │ │ 4 │ 键盘 │ 399 │ │ │ └─────┴──────────┴───────┘ │ └─────────────────────────────────────────────────────────┘ ↓ 步骤4:聚合函数(对每组独立计算) ┌─────────────────────────────────────────────────────────┐ │ 组1 - 数码: │ │ COUNT(*) = 3 │ │ SUM(price) = 2999+5999+199 = 9197 │ │ AVG(price) = 9197 / 3 = 3065.67 │ │ │ │ 组2 - 外设: │ │ COUNT(*) = 1 │ │ SUM(price) = 399 │ │ AVG(price) = 399 │ └─────────────────────────────────────────────────────────┘ ↓ 步骤5:HAVING(无,跳过) ↓ 步骤6:SELECT(选择要显示的列) ┌──────────┬────────────┬────────────┬────────────┐ │ category │ 商品数量 │ 分类总金额 │ 分类平均价 │ ├──────────┼────────────┼────────────┼────────────┤ │ 数码 │ 3 │ 9197 │ 3065.67 │ │ 外设 │ 1 │ 399 │ 399 │ └──────────┴────────────┴────────────┴────────────┘ ↓ 步骤7:ORDER BY 分类总金额 DESC ┌──────────┬────────────┬────────────┬────────────┐ │ category │ 商品数量 │ 分类总金额 │ 分类平均价 │ ├──────────┼────────────┼────────────┼────────────┤ │ 数码 │ 3 │ 9197 │ 3065.67 │ │ 外设 │ 1 │ 399 │ 399 │ └──────────┴────────────┴────────────┴────────────┘
五、关键规则总结
| 规则 | 说明 | 示例 |
|---|---|---|
| 聚合函数输入多行,输出一行 | 把一组数据压缩成一个值 | SUM(price) |
| WHERE 在聚合之前执行 | 先筛选行,再分组聚合 | WHERE price > 100 |
| 没有 GROUP BY 时,整表为一组 | 所有行聚合成一行结果 | SELECT COUNT(*) FROM t |
| 有 GROUP BY 时,每组输出一行 | 分组数 = 结果行数 | GROUP BY category |
| SELECT 中的非聚合列必须在 GROUP BY 中 | 语法规则 | SELECT category, COUNT(*) ... GROUP BY category |
| HAVING 在聚合之后执行 | 过滤分组结果 | HAVING COUNT(*) > 5 |
六、常见错误示例
错误1:SELECT 中的列不在 GROUP BY 中
sql
-- ❌ 错误:name 既不在 GROUP BY 中,也不是聚合函数SELECT category, name, COUNT(*) FROM products GROUP BY category;-- ✅ 正确:name 要么在 GROUP BY 中,要么用聚合函数SELECT category, MIN(name), COUNT(*) FROM products GROUP BY category;
错误2:WHERE 中使用聚合函数
sql
-- ❌ 错误:WHERE 在聚合之前执行,不认识聚合函数SELECT category, COUNT(*) FROM products WHERE COUNT(*) > 5 GROUP BY category;-- ✅ 正确:用 HAVINGSELECT category, COUNT(*) FROM products GROUP BY category HAVING COUNT(*) > 5;
七、总结
| 步骤 | 作用 | 能否使用聚合函数 |
|---|---|---|
FROM | 确定数据来源 | ❌ 不能 |
WHERE | 筛选原始行 | ❌ 不能 |
GROUP BY | 分组 | ❌ 不能 |
| 聚合函数 | 对每组计算 | ✅ 这里执行 |
HAVING | 筛选分组结果 | ✅ 能 |
SELECT | 选择显示列 | ✅ 能 |
ORDER BY | 排序 | ✅ 能 |
一句话总结:SQL 中聚合函数的执行顺序是:先 FROM 确定数据源,然后 WHERE 筛选行,再 GROUP BY 分组,接着聚合函数对每组进行计算,之后 HAVING 筛选分组结果,最后 SELECT 显示、ORDER BY 排序。理解这个顺序,就能明白为什么 WHERE 不能用聚合函数、而 HAVING 可以