前言上两篇讲了SQL查询基础和数据操作这篇讲SQL数据分析最核心的一块聚合函数与分组统计。说实话在实际工作中90%的数据分析需求都离不开GROUP BY。各品类销售额是多少每个用户下了几单月度GMV走势怎么样——这些问题全靠聚合函数分组来实现。很多同学学了SELECT和WHERE就以为自己会SQL了结果一到面试或实际工作中被问统计各门店Top3商品直接卡壳。建议先看完前两篇SQL入门增删改查再看这篇效果翻倍。〇、建表与数据准备沿用电商订单表新增一些数据让聚合统计更有意义。-- -- 电商订单表 orders扩展数据版 -- 公众号船长Talk -- CREATE TABLE IF NOT EXISTS orders ( order_id INT PRIMARY KEY COMMENT 订单ID, customer VARCHAR(50) COMMENT 客户姓名, product VARCHAR(100) COMMENT 商品名称, category VARCHAR(50) COMMENT 商品分类, price DECIMAL(10,2) COMMENT 单价, quantity INT COMMENT 购买数量, total_amount DECIMAL(10,2) COMMENT 订单总金额, order_date DATE COMMENT 下单日期, status VARCHAR(20) COMMENT 订单状态 ); -- 插入测试数据20条覆盖多分类、多客户、多日期 INSERT INTO orders VALUES (1, 张三, iPhone 15, 手机, 7999.00, 1, 7999.00, 2026-04-01, 已完成), (2, 李四, MacBook Pro, 电脑, 14999.00, 1, 14999.00, 2026-04-01, 已完成), (3, 张三, AirPods Pro, 配件, 999.00, 2, 1998.00, 2026-04-02, 已完成), (4, 王五, iPhone 15, 手机, 7999.00, 1, 7999.00, 2026-04-02, 已取消), (5, 赵六, iPad Air, 平板, 4799.00, 2, 9598.00, 2026-04-03, 已完成), (6, 李四, Apple Watch, 配件, 2999.00, 1, 2999.00, 2026-04-03, 已完成), (7, 张三, MacBook Pro, 电脑, 14999.00, 1, 14999.00, 2026-04-04, 已完成), (8, 王五, Magic Keyboard, 配件, 1999.00, 1, 1999.00, 2026-04-05, 已退款), (9, 赵六, iPhone 15, 手机, 7999.00, 1, 7999.00, 2026-04-05, 已完成), (10, 张三, HomePod mini, 配件, 749.00, 2, 1498.00, 2026-04-06, 已完成), (11, 钱七, iPhone 15, 手机, 7999.00, 2, 15998.00, 2026-04-06, 已完成), (12, 李四, iPad Air, 平板, 4799.00, 1, 4799.00, 2026-04-07, 已完成), (13, 孙八, AirPods Pro, 配件, 999.00, 1, 999.00, 2026-04-07, 待发货), (14, 王五, MacBook Air, 电脑, 8999.00, 1, 8999.00, 2026-04-08, 已完成), (15, 张三, Apple Pencil, 配件, 999.00, 1, 999.00, 2026-04-08, 已完成), (16, 赵六, Magic Keyboard, 配件, 1999.00, 1, 1999.00, 2026-04-09, 已发货), (17, 钱七, MacBook Pro, 电脑, 14999.00, 1, 14999.00, 2026-04-09, 已完成), (18, 李四, HomePod mini, 配件, 749.00, 3, 2247.00, 2026-04-10, 待发货), (19, 张三, iPad Air, 平板, 4799.00, 1, 4799.00, 2026-04-10, 已完成), (20, 孙八, iPhone 15, 手机, 7999.00, 1, 7999.00, 2026-04-10, 已完成);20条数据覆盖5个分类手机、电脑、配件、平板、6个客户、10天日期。后面所有例子都基于这张表。一、5大聚合函数聚合函数就是把多行数据压缩成一个值的函数。SQL内置了5个核心聚合函数搞懂这5个日常分析基本够用。1.1 COUNT —— 计数-- -- COUNT 用法 -- 公众号船长Talk -- -- 总订单数所有行 SELECT COUNT(*) AS 总订单数 FROM orders; -- 结果20 -- 已完成订单数加条件 SELECT COUNT(*) AS 已完成订单数 FROM orders WHERE status 已完成; -- 结果14 -- 有效订单数排除NULL排除已取消/已退款 SELECT COUNT(*) AS 有效订单数 FROM orders WHERE status NOT IN (已取消, 已退款); -- 结果17 -- COUNT(*) vs COUNT(列名) 的区别 -- COUNT(*)统计所有行包括NULL -- COUNT(列名)统计该列非NULL的值 SELECT COUNT(*) AS 总行数, COUNT(status) AS 状态非空行数 FROM orders; -- 如果status列有NULL两者结果不同面试坑点COUNT(*)和COUNT(列名)不一定相等。COUNT(*)统计所有行COUNT(列名)跳过NULL值。面试官爱问这个。1.2 SUM —— 求和-- -- SUM 用法 -- 公众号船长Talk -- -- 总销售额所有订单金额加起来 SELECT SUM(total_amount) AS 总销售额 FROM orders; -- 结果139574.00 -- 已完成订单的总销售额 SELECT SUM(total_amount) AS 已完成销售额 FROM orders WHERE status 已完成; -- 结果110777.00 -- 各客户消费总额 SELECT customer AS 客户, SUM(total_amount) AS 消费总额 FROM orders WHERE status 已完成 GROUP BY customer ORDER BY 消费总额 DESC; -- 结果张三 31292, 李四 25044, 钱七 30997, 赵六 19596, 王五 8999, 孙八 7999实战提醒SUM只对数值列有效。对字符串列SUM会返回0不会报错。所以SUM之前先确认列的数据类型。1.3 AVG —— 平均值-- -- AVG 用法 -- 公众号船长Talk -- -- 平均订单金额 SELECT AVG(total_amount) AS 平均订单金额 FROM orders; -- 结果6978.70 -- 各分类的平均订单金额 SELECT category AS 分类, AVG(total_amount) AS 平均订单金额, COUNT(*) AS 订单数 FROM orders WHERE status 已完成 GROUP BY category ORDER BY 平均订单金额 DESC; -- 电脑最高配件最低 -- ⚠️ AVG 的陷阱NULL值不参与计算 -- 如果某行 total_amount 是 NULL它不参与AVG的分母 -- 想包含NULL当0处理用 COALESCE SELECT AVG(COALESCE(total_amount, 0)) AS 含NULL的平均值 FROM orders;避坑指南AVG的一个大坑是——1笔99999的订单和9笔100的订单平均是10999.8但真实水平其实更接近100。均值容易被极端值拉偏这种情况考虑用中位数后文讲。1.4 MAX / MIN —— 最大值 / 最小值-- -- MAX / MIN 用法 -- 公众号船长Talk -- -- 最大/最小订单金额 SELECT MAX(total_amount) AS 最大订单金额, MIN(total_amount) AS 最小订单金额, MAX(total_amount) - MIN(total_amount) AS 极差 FROM orders; -- 结果15998 / 999 / 14999 -- 最大/最小下单日期查看数据时间范围 SELECT MIN(order_date) AS 最早下单日期, MAX(order_date) AS 最晚下单日期 FROM orders; -- 结果2026-04-01 / 2026-04-10 -- 实战场景每个客户的最近一次购买日期RFM模型中的Recency SELECT customer AS 客户, MAX(order_date) AS 最近购买日期 FROM orders GROUP BY customer ORDER BY 最近购买日期 DESC; -- 这个查询是RFM用户分层的基础实战技巧MAX/MIN不只用于数字也常用于日期。计算最近登录时间最早上岗日期都是这个套路。二、GROUP BY —— 分组统计的核心GROUP BY是SQL数据分析的灵魂。没有GROUP BY聚合函数只能算全表的一个值加了GROUP BY就能按维度拆开算。打个比方COUNT(*)是一共有多少订单加了GROUP BY category就是每个品类有多少订单。2.1 单维度分组-- -- GROUP BY 单维度分组 -- 公众号船长Talk -- -- 各品类的订单数量和销售额 SELECT category AS 品类, COUNT(*) AS 订单数, SUM(total_amount) AS 总销售额, AVG(total_amount) AS 平均订单金额 FROM orders WHERE status 已完成 GROUP BY category ORDER BY 总销售额 DESC; -- 结果示例 -- | 品类 | 订单数 | 总销售额 | 平均订单金额 | -- | 电脑 | 4 | 52996 | 13249.00 | -- | 手机 | 4 | 39995 | 9998.75 | -- | 配件 | 3 | 7742 | 2580.67 | -- | 平板 | 3 | 19195 | 6398.33 |2.2 多维度分组-- 多维度分组品类 客户 SELECT category AS 品类, customer AS 客户, COUNT(*) AS 订单数, SUM(total_amount) AS 消费总额 FROM orders WHERE status 已完成 GROUP BY category, customer ORDER BY 品类, 消费总额 DESC; -- 可以看出每个客户在哪个品类花了多少钱关键原则SELECT后面的列要么出现在GROUP BY里要么被聚合函数包裹。否则SQL会报错。-- ❌ 错误写法customer没有出现在GROUP BY中也没有被聚合 SELECT customer, category, COUNT(*) FROM orders GROUP BY category; -- ✅ 正确写法把customer加到GROUP BY SELECT customer, category, COUNT(*) FROM orders GROUP BY customer, category;2.3 GROUP BY 日期处理-- -- 按日期/月份 分组统计 -- 公众号船长Talk -- -- 按天统计每日销售额 SELECT order_date AS 日期, COUNT(*) AS 订单数, SUM(total_amount) AS 日销售额 FROM orders WHERE status 已完成 GROUP BY order_date ORDER BY 日期; -- 按月统计DATE_FORMATMySQL语法 SELECT DATE_FORMAT(order_date, %Y-%m) AS 月份, COUNT(*) AS 订单数, SUM(total_amount) AS 月销售额 FROM orders GROUP BY DATE_FORMAT(order_date, %Y-%m) ORDER BY 月份; -- 按周统计YEARWEEK函数 SELECT YEARWEEK(order_date, 1) AS 周次, COUNT(*) AS 订单数, SUM(total_amount) AS 周销售额 FROM orders GROUP BY YEARWEEK(order_date, 1) ORDER BY 周次;三、HAVING —— 分组后的条件过滤WHERE过滤行HAVING过滤组。这是新手最容易搞混的两个关键字。一句话记WHERE在GROUP BY之前执行过滤原始行HAVING在GROUP BY之后执行过滤聚合结果。-- -- HAVING 用法 -- 公众号船长Talk -- -- ❌ 错误WHERE里不能用聚合函数 -- SELECT category, SUM(total_amount) FROM orders WHERE SUM(total_amount) 10000 GROUP BY category; -- ✅ 正确用HAVING过滤聚合结果 SELECT category AS 品类, SUM(total_amount) AS 总销售额 FROM orders WHERE status 已完成 -- 先过滤只要已完成订单 GROUP BY category HAVING SUM(total_amount) 10000 -- 再过滤品类总销售额 10000 ORDER BY 总销售额 DESC; -- 结果电脑(52996)、手机(39995)、平板(19195)配件被过滤掉 -- 实战场景找出消费超过2次的客户 SELECT customer AS 客户, COUNT(*) AS 订单数, SUM(total_amount) AS 消费总额 FROM orders WHERE status 已完成 GROUP BY customer HAVING COUNT(*) 2 ORDER BY 消费总额 DESC; -- 结果张三、李四、赵六、钱七都有2单以上 -- 实战场景每个品类中平均订单金额高于5000的 SELECT category AS 品类, AVG(total_amount) AS 平均订单金额, COUNT(*) AS 订单数 FROM orders WHERE status 已完成 GROUP BY category HAVING AVG(total_amount) 5000 ORDER BY 平均订单金额 DESC;执行顺序速记FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BYWHERE先过滤原始数据GROUP BY分组HAVING再过滤分组结果。别搞反了。四、组合统计一次查询出完整报告工作中最常见的需求一张表搞出完整的统计报告。4.1 多维度综合统计-- -- 综合统计报告 -- 公众号船长Talk -- -- 各品类的完整统计订单数/销售额/平均金额/最大单笔/最小单笔 SELECT category AS 品类, COUNT(*) AS 订单数, SUM(total_amount) AS 总销售额, ROUND(AVG(total_amount), 2) AS 平均订单金额, MAX(total_amount) AS 最大单笔, MIN(total_amount) AS 最小单笔, COUNT(DISTINCT customer) AS 客户数 FROM orders WHERE status 已完成 GROUP BY category ORDER BY 总销售额 DESC; -- 一次查询7个指标一份完整的品类分析报告4.2 CASE WHEN 聚合条件聚合-- -- CASE WHEN 条件聚合 高频面试题 -- 公众号船长Talk -- -- 各品类的已完成/已取消/待发货订单数一次查询搞定 SELECT category AS 品类, COUNT(*) AS 总订单数, SUM(CASE WHEN status 已完成 THEN 1 ELSE 0 END) AS 已完成, SUM(CASE WHEN status 已取消 THEN 1 ELSE 0 END) AS 已取消, SUM(CASE WHEN status 待发货 THEN 1 ELSE 0 END) AS 待发货, SUM(CASE WHEN status 已退款 THEN 1 ELSE 0 END) AS 已退款, ROUND( SUM(CASE WHEN status 已完成 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 1 ) AS 完成率% FROM orders GROUP BY category ORDER BY 总订单数 DESC; -- 这个技巧叫条件聚合能在一行里做多次统计 -- 不需要写多个查询一次GROUP BY搞定所有维度的交叉统计 -- 面试高频题必会条件聚合是数据分析师的看家本领。不会这个报表需求一来就得写十几个查询效率低下。4.3 ROLLUP —— 小计与总计-- -- ROLLUP 生成小计和总计 -- 公众号船长Talk -- -- 各品类 总计MySQL语法 SELECT IFNULL(category, 【总计】) AS 品类, COUNT(*) AS 订单数, SUM(total_amount) AS 总销售额 FROM orders WHERE status 已完成 GROUP BY category WITH ROLLUP; -- 结果多一行品类【总计】订单数14总销售额110777 -- 多维度ROLLUP品类 客户 小计 总计 SELECT IFNULL(category, 【小计】) AS 品类, IFNULL(customer, 【合计】) AS 客户, COUNT(*) AS 订单数, SUM(total_amount) AS 总销售额 FROM orders WHERE status 已完成 GROUP BY category, customer WITH ROLLUP; -- 结果包含每个品类每个客户的明细 品类小计 总计 -- 适合直接导Excel当报表用五、实战场景从需求到SQL最后用3个真实工作场景把上面的知识点串起来。5.1 场景一月度销售看板-- -- 实战月度销售看板 -- 公众号船长Talk -- -- 按日期统计附带环比增长率 SELECT order_date AS 日期, COUNT(*) AS 订单数, SUM(total_amount) AS 日销售额, -- 环比和前一天对比 ROUND( (SUM(total_amount) - LAG(SUM(total_amount), 1) OVER (ORDER BY order_date)) / LAG(SUM(total_amount), 1) OVER (ORDER BY order_date) * 100, 1 ) AS 环比增长率% FROM orders WHERE status 已完成 GROUP BY order_date ORDER BY 日期; -- LAG是窗口函数这里先用GROUP BY算出每天的值再和前一天对比5.2 场景二用户RFM分层-- -- 实战用户RFM分层简化版 -- 公众号船长Talk -- R 最近购买天数越小越好 -- F 购买频次越多越好 -- M 累计消费金额越多越好 -- SELECT customer AS 客户, DATEDIFF(CURRENT_DATE(), MAX(order_date)) AS R-最近购买天数, COUNT(*) AS F-购买频次, SUM(total_amount) AS M-累计消费, -- 简单分层R5且F2且M10000为高价值客户 CASE WHEN DATEDIFF(CURRENT_DATE(), MAX(order_date)) 5 AND COUNT(*) 2 AND SUM(total_amount) 10000 THEN ⭐ 高价值 WHEN COUNT(*) 2 THEN 活跃客户 WHEN DATEDIFF(CURRENT_DATE(), MAX(order_date)) 7 THEN ⚠️ 流失风险 ELSE 普通客户 END AS 客户分层 FROM orders WHERE status 已完成 GROUP BY customer ORDER BY M-累计消费 DESC;5.3 场景三各品类Top1商品-- -- 实战各品类销售额最高的商品 -- 公众号船长Talk -- SELECT category AS 品类, product AS 商品, total_amount AS 销售额, quantity AS 销量 FROM orders o1 WHERE status 已完成 AND total_amount ( -- 子查询找该品类最大订单金额 SELECT MAX(total_amount) FROM orders o2 WHERE o2.category o1.category AND o2.status 已完成 ) ORDER BY 销售额 DESC; -- 如果一个品类有多个最大值上面会返回多行 -- 只要一个的话可以在外面包一层 LIMIT SELECT * FROM ( SELECT category AS 品类, product AS 商品, total_amount AS 销售额 FROM orders o1 WHERE status 已完成 AND total_amount ( SELECT MAX(total_amount) FROM orders o2 WHERE o2.category o1.category AND o2.status 已完成 ) GROUP BY category ORDER BY 销售额 DESC ) t GROUP BY 品类;六、聚合函数速查表-- -- 聚合函数速查表 -- 公众号船长Talk -- -- 1. COUNT(*) → 统计所有行 -- 2. COUNT(列名) → 统计非NULL行 -- 3. COUNT(DISTINCT 列名) → 统计去重后的数量 -- 4. SUM(列名) → 求和 -- 5. AVG(列名) → 平均值注意极端值影响 -- 6. MAX(列名) → 最大值 -- 7. MIN(列名) → 最小值 -- 8. GROUP BY → 按列分组 -- 9. HAVING → 过滤分组结果WHERE过滤原始行 -- 10. WITH ROLLUP → 生成小计和总计 -- 11. CASE WHEN聚合 → 条件聚合一次查询多个维度统计 -- 执行顺序 -- FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY总结聚合函数 GROUP BY是SQL数据分析的吃饭家伙。5个聚合函数COUNT/SUM/AVG/MAX/MIN GROUP BY HAVING能解决90%的统计需求。进阶技巧条件聚合CASE WHEN SUM是面试高频考点工作中也极其常用务必掌握。下一篇预告《SQL多表查询完全指南JOIN的7种用法详解》讲怎么把多张表关联起来查询。这是SQL从能查到查得好的关键一步。觉得有用点赞收藏关注船长Talk每天学一点数据分析实战技能。 SQL数据分析系列① SQL零基础入门10个语句解决80%的查询问题② SQL数据操作完全指南增删改查实战详解③SQL聚合函数与分组统计数据分析核心技能本文④ SQL多表查询完全指南JOIN的7种用法详解下一篇