2.20 基础聚合函数(COUNT、SUM、AVG、MAX、MIN)
在电商数据分析中,你几乎每天都要用到聚合函数:
统计总订单数(
COUNT)。计算总销售额(
SUM)。求平均客单价(
AVG)。找最高/最低金额(
MAX/MIN)。
这一章我会带你彻底搞懂五个最常用的聚合函数:COUNT、SUM、AVG、MAX、MIN。学完之后,你能独立完成电商核心经营指标的一站式统计。
学习前准备:
已完成MySQL安装(参考系列前几章)
已安装DBeaver或Navicat
准备一个练习数据库,比如
agg_demo
学习前环境准备
步骤1:确保MySQL服务已启动。
步骤2:创建练习数据库和表,并插入示例数据。
CREATEDATABASEagg_demoCHARACTERSETutf8mb4COLLATEutf8mb4_unicode_ci;USEagg_demo;-- 订单表CREATETABLEorders(order_idINTPRIMARYKEYAUTO_INCREMENT,user_idINTNOTNULL,shop_nameVARCHAR(50)NOTNULL,product_nameVARCHAR(100),amountDECIMAL(10,2)NOTNULL,quantityINTNOTNULLDEFAULT1,order_statusVARCHAR(20)NOTNULL,create_timeDATETIMENOTNULL);INSERTINTOorders(user_id,shop_name,product_name,amount,quantity,order_status,create_time)VALUES(1001,'女装旗舰店','碎花连衣裙',299.00,2,'已支付','2025-06-01 10:00:00'),(1002,'女装旗舰店','纯棉T恤',189.00,3,'已取消','2025-06-01 11:00:00'),(1003,'男装专营店','牛仔裤',599.00,1,'已支付','2025-06-02 09:30:00'),(1001,'女装旗舰店','雪纺衫',399.00,1,'已支付','2025-06-03 14:20:00'),(1004,'童装店','儿童T恤',99.00,5,'已完成','2025-06-03 16:00:00'),(1005,'女装旗舰店','真丝连衣裙',1299.00,1,'已支付','2025-06-04 08:30:00'),(1002,'男装专营店','休闲短裤',89.00,2,'已取消','2025-06-04 10:00:00'),(1006,'女装旗舰店','基础打底衫',89.00,10,'已支付','2025-06-05 09:00:00'),(1007,'男装专营店','Polo衫',259.00,1,'已支付','2025-06-05 14:00:00');聚合函数基础认知
聚合函数对一组值执行计算,返回单个结果。它们通常与GROUP BY配合使用,也可以单独用于全表统计。
常用聚合函数:
| 函数 | 作用 | 电商示例 |
|---|---|---|
COUNT() | 计数 | 订单数、用户数 |
SUM() | 求和 | GMV、销量 |
AVG() | 平均值 | 客单价、件单价 |
MAX() | 最大值 | 最高订单金额 |
MIN() | 最小值 | 最低商品售价 |
执行逻辑:聚合函数会在WHERE筛选之后、GROUP BY分组之后对每组进行计算。 |
我的踩坑经历:第一次用
COUNT(*)时,我以为COUNT(column)和COUNT(*)一样,后来发现COUNT(column)会忽略NULL值,导致计数偏少。从此我根据需求选择正确的形式。
COUNT函数详解(计数)
4.1 基础语法
COUNT(*)-- 统计所有行(包括NULL)COUNT(列名)-- 统计该列非NULL的行数COUNT(DISTINCT列名)-- 统计去重后的数量4.2 电商实操案例
案例一:统计总订单数
SELECTCOUNT(*)AStotal_ordersFROMorders;预期结果:9。
案例二:统计已支付订单数
SELECTCOUNT(*)ASpaid_ordersFROMordersWHEREorder_status='已支付';预期结果:6(ORD001、ORD003、ORD004、ORD006、ORD008、ORD009)。
案例三:统计有商品名称的订单数(排除NULL)
假设没有NULL,演示用法。
SELECTCOUNT(product_name)AShas_product_nameFROMorders;案例四:统计独立用户数(去重)
SELECTCOUNT(DISTINCTuser_id)ASunique_usersFROMorders;预期结果:7(1001,1002,1003,1004,1005,1006,1007)。
4.3 分步操作
确定要统计的对象(所有行、某列非空、去重)。
加上
WHERE条件(如果需要)。执行并验证。
避坑提醒:
COUNT(*)和COUNT(1)性能几乎相同,推荐用COUNT(*)。COUNT(column)会忽略NULL,如果不确定是否有NULL,用COUNT(*)更安全。
实操避坑提醒:统计用户数时,必须用
COUNT(DISTINCT user_id),否则同一用户多单会被重复计数。
SUM函数详解(求和)
5.1 基础语法
SUM(列名)-- 对数值列求和,自动忽略NULL5.2 电商实操案例
案例一:计算全店GMV(已支付订单总金额)
SELECTSUM(amount)ASgmvFROMordersWHEREorder_status='已支付';预期结果:299+599+399+1299+89+259 = 2944? 计算:299+599=898,+399=1297,+1299=2596,+89=2685,+259=2944。正确。
案例二:计算女装旗舰店的总销量(数量)
SELECTSUM(quantity)AStotal_quantityFROMordersWHEREshop_name='女装旗舰店';预期结果:2+3+1+1+10 = 17? 注意ORD002是已取消但数量也计入?通常只计有效订单,需要加order_status条件。
SELECTSUM(quantity)AStotal_quantityFROMordersWHEREshop_name='女装旗舰店'ANDorder_status='已支付';预期结果:ORD001(2), ORD004(1), ORD006(1), ORD008(10) = 14。
案例三:计算退款总金额(假设退款订单状态为“已取消”)
SELECTSUM(amount)ASrefund_amountFROMordersWHEREorder_status='已取消';预期结果:189+89=278。
5.3 分步操作
筛选有效订单(
WHERE)。对需要求和的列使用
SUM。执行验证。
避坑提醒:
SUM自动忽略NULL,但不会忽略字符串。确保列是数值类型。对金额列求和时,注意单位一致(如都是元)。
我的踩坑经历:我写过
SUM(amount),结果amount列里混了一个文本“N/A”,导致整个求和结果为NULL。从那以后,我每次都会先检查数据类型。
AVG函数详解(平均值)
6.1 基础语法
AVG(列名)-- 对数值列求平均值,自动忽略NULL6.2 电商实操案例
案例一:计算全店平均客单价(已支付订单的平均金额)
SELECTAVG(amount)ASavg_order_valueFROMordersWHEREorder_status='已支付';预期结果:2944 / 6 ≈ 490.67。
案例二:计算女装旗舰店已支付订单的平均件单价(金额/数量?这里简化:平均每笔订单金额)
SELECTAVG(amount)FROMordersWHEREshop_name='女装旗舰店'ANDorder_status='已支付';预期结果:(299+399+1299+89)/4 = 2086/4=521.5。
案例三:计算每个用户平均下单金额(需配合GROUP BY,但这里先演示整体)
SELECTAVG(amount)FROMordersWHEREorder_status='已支付';6.3 分步操作
筛选数据。
用
AVG计算。执行验证。
避坑提醒:
AVG只对数值列有效。AVG会忽略NULL,但不会忽略0。0会拉低平均值,要根据业务决定是否排除。
实操避坑提醒:客单价 = GMV / 订单数,不等于
AVG(amount)吗?是的,因为AVG(amount)就是总金额除以订单数。但如果订单有多个商品,amount已经是订单总金额,那么AVG(amount)就是客单价。
MAX/MIN函数详解(最大/最小值)
7.1 基础语法
MAX(列名)-- 最大值MIN(列名)-- 最小值7.2 电商实操案例
案例一:找出最高订单金额
SELECTMAX(amount)ASmax_amountFROMorders;预期结果:1299。
案例二:找出最低订单金额(已支付订单)
SELECTMIN(amount)ASmin_amountFROMordersWHEREorder_status='已支付';预期结果:89(ORD008)。
案例三:找出最早和最晚的下单时间
SELECTMIN(create_time)ASfirst_order,MAX(create_time)ASlast_orderFROMorders;预期结果:2025-06-01 10:00:00 和 2025-06-05 14:00:00。
案例四:在商品表中找出最高和最低价格(假设有商品表)
-- 创建商品表CREATETABLEproducts(product_idINTPRIMARYKEY,product_nameVARCHAR(100),priceDECIMAL(10,2));INSERTINTOproductsVALUES(1,'连衣裙',299),(2,'T恤',89),(3,'牛仔裤',199);SELECTMAX(price),MIN(price)FROMproducts;7.3 分步操作
筛选条件(可选)。
用
MAX或MIN。执行验证。
避坑提醒:
MAX/MIN对文本列按字典序比较。对日期列也能正确比较。
我的踩坑经历:我用
MAX(product_name)找最晚的商品名称,结果返回了字典序最大的,不是按时间。排序和聚合要分清。
多个聚合函数的组合用法
8.1 基础语法
可以在一个SELECT中同时使用多个聚合函数,得到一站式统计。
SELECTCOUNT(*)AStotal_orders,SUM(amount)ASgmv,AVG(amount)ASavg_price,MAX(amount)ASmax_price,MIN(amount)ASmin_priceFROMordersWHEREorder_status='已支付';8.2 电商实操案例
案例一:全店经营核心指标(已支付订单)
SELECTCOUNT(*)ASorder_cnt,SUM(amount)ASgmv,ROUND(AVG(amount),2)ASavg_order_value,MAX(amount)ASmax_order,MIN(amount)ASmin_orderFROMordersWHEREorder_status='已支付';预期结果:order_cnt=6, gmv=2944, avg_order_value=490.67, max=1299, min=89。
案例二:女装旗舰店的销售汇总
SELECTCOUNT(*)ASorders,SUM(amount)ASgmv,SUM(quantity)ASitems_sold,AVG(amount)ASavg_price,MAX(amount)AShighest,MIN(amount)ASlowestFROMordersWHEREshop_name='女装旗舰店'ANDorder_status='已支付';预期结果:orders=4, gmv=2086, items_sold=14, avg_price=521.5, highest=1299, lowest=89。
案例三:按店铺分组统计(预告下一章内容,这里简单展示)
SELECTshop_name,COUNT(*)ASorder_cnt,SUM(amount)ASgmvFROMordersWHEREorder_status='已支付'GROUPBYshop_name;8.3 分步操作
确定要统计的指标。
写出所有聚合函数,给别名。
添加
WHERE条件(可选)。执行并验证。
避坑提醒:
聚合函数不能与普通列混用(除非有
GROUP BY)。例如SELECT order_id, COUNT(*) FROM orders会报错。多个聚合函数互相独立,计算顺序不影响结果。
实操避坑提醒:在计算平均值前,如果要去除异常值,可以在
WHERE中先过滤。例如WHERE amount BETWEEN 10 AND 10000。
综合实操案例:服饰类目店铺月度经营核心指标统计
9.1 案例背景
某服饰类目店铺需要生成一份6月份的经营汇总报表,包含以下指标:
总订单数(所有状态)。
有效订单数(已支付+已完成)。
GMV(已支付+已完成的金额总和)。
客单价(GMV / 有效订单数)。
最高订单金额、最低订单金额。
总销量(数量总和,有效订单)。
独立用户数(去重)。
9.2 分步操作
步骤1:总订单数
SELECTCOUNT(*)AStotal_ordersFROMordersWHEREcreate_timeBETWEEN'2025-06-01'AND'2025-06-30';步骤2:有效订单数
SELECTCOUNT(*)ASvalid_ordersFROMordersWHEREorder_statusIN('已支付','已完成')ANDcreate_timeBETWEEN'2025-06-01'AND'2025-06-30';步骤3:GMV
SELECTSUM(amount)ASgmvFROMordersWHEREorder_statusIN('已支付','已完成')ANDcreate_timeBETWEEN'2025-06-01'AND'2025-06-30';步骤4:客单价
SELECTROUND(SUM(amount)/COUNT(*),2)ASavg_order_valueFROMordersWHEREorder_statusIN('已支付','已完成')ANDcreate_timeBETWEEN'2025-06-01'AND'2025-06-30';步骤5:最高/最低订单金额(有效订单)
SELECTMAX(amount)ASmax_amount,MIN(amount)ASmin_amountFROMordersWHEREorder_statusIN('已支付','已完成')ANDcreate_timeBETWEEN'2025-06-01'AND'2025-06-30';步骤6:总销量(有效订单的数量总和)
SELECTSUM(quantity)AStotal_itemsFROMordersWHEREorder_statusIN('已支付','已完成')ANDcreate_timeBETWEEN'2025-06-01'AND'2025-06-30';步骤7:独立用户数(有效订单)
SELECTCOUNT(DISTINCTuser_id)ASunique_usersFROMordersWHEREorder_statusIN('已支付','已完成')ANDcreate_timeBETWEEN'2025-06-01'AND'2025-06-30';步骤8:一站式查询(组合)
SELECTCOUNT(*)AStotal_orders,SUM(CASEWHENorder_statusIN('已支付','已完成')THEN1ELSE0END)ASvalid_orders,SUM(CASEWHENorder_statusIN('已支付','已完成')THENamountELSE0END)ASgmv,ROUND(SUM(CASEWHENorder_statusIN('已支付','已完成')THENamountELSE0END)/NULLIF(SUM(CASEWHENorder_statusIN('已支付','已完成')THEN1ELSE0END),0),2)ASavg_order_value,MAX(CASEWHENorder_statusIN('已支付','已完成')THENamountELSENULLEND)ASmax_amount,MIN(CASEWHENorder_statusIN('已支付','已完成')THENamountELSENULLEND)ASmin_amount,SUM(CASEWHENorder_statusIN('已支付','已完成')THENquantityELSE0END)AStotal_items,COUNT(DISTINCTCASEWHENorder_statusIN('已支付','已完成')THENuser_idEND)ASunique_usersFROMordersWHEREcreate_timeBETWEEN'2025-06-01'AND'2025-06-30';9.3 结果验证
执行一站式查询,检查数据逻辑(如客单价 = GMV / 有效订单数)。
📌 电商数据合规提示:在统计独立用户数时,使用内部匿名
user_id,不要涉及手机号等敏感信息。汇总指标(如GMV、客单价)属于经营数据,内部共享时注意权限控制。
本章踩坑清单与合规总结
10.1 新手常见踩坑
| 错误 | 原因 | 正确做法 |
|---|---|---|
COUNT(column)忽略NULL导致计数偏少 | 不理解NULL处理 | 用COUNT(*)或确保列非空 |
| 金额列包含非数字字符 | 求和结果为0或NULL | 先清洗数据,转换类型 |
AVG包含0值 | 0拉低平均值 | 根据业务决定是否排除0 |
聚合函数与普通列混用无GROUP BY | 语法错误 | 要么全聚合,要么加GROUP BY |
SUM(amount)未过滤无效订单 | 统计了退款订单 | 加WHERE order_status = '已支付' |
10.2 性能优化建议
为
WHERE条件中的列(如create_time、order_status)建立索引。避免在聚合函数中使用
DISTINCT处理大数据量,可先用子查询去重。
10.3 电商数据合规红线
统计指标不要包含个人标识:如统计用户数时,只输出数字,不输出用户ID列表。
GMV等核心指标:内部报表需加密传输,避免泄露。
退款金额统计:注意区分“退款”和“取消”,业务定义要清晰。
结语
聚合函数是SQL统计分析的基石。掌握COUNT、SUM、AVG、MAX、MIN,你就能独立计算电商核心经营指标。
有问题的评论区留言,我看到会回复。