ABC分类是按销售额累计占比划分客户/商品等级:A类占60%、B类占30%、C类占10%;不能用GROUP BY因其打散行序,破坏窗口函数SUM() OVER (ORDER BY ...)所需的全局有序累积。

什么是ABC分类,为什么不能用GROUP BY直接做
ABC分类本质是按销售额(或其他指标)累计占比划分客户/商品等级:A类占累计60%、B类占接下来30%、C类占剩余10%。很多人第一反应是先GROUP BY聚合再排序,但问题在于——累计占比必须基于全局有序的行级累积,而GROUP BY会打散原始行序,无法支撑SUM() OVER (ORDER BY ...)这类窗口计算。
关键点在于:ABC分类不是分组统计,而是对明细行按指标排序后,逐行累加并打标。
核心SQL结构:ORDER BY + SUM() OVER + CASE WHEN
实际执行分三步走,缺一不可:
- 先按销售额降序排列所有行(
ORDER BY sales DESC) - 用
SUM(sales) OVER (ORDER BY sales DESC)算出每行的累计销售额 - 再用
SUM(sales) OVER ()拿到总销售额,二者相除得累计占比 - 最后用
CASE WHEN按阈值打标(如累计占比≤0.6 → 'A')
SUM(sales) OVER ()
- 确保
sales字段有索引(单列或作为联合索引前导列) - 若只关心Top N(比如只标前1000个A类),可在子查询里先
LIMIT再算累计——但注意:这会让累计占比失真,仅适用于近似场景 - 更稳妥的做法是把累计逻辑下推到应用层:用游标遍历排序结果,边读边累加。适合千万级以上明细且对实时性要求不高的批处理
ABC分类真正的复杂点不在SQL语法,而在业务定义是否闭环:累计占比阈值是固定值还是动态调整?是否要排除退货/测试订单?这些逻辑一旦掺进SQL,就很难维护。不如把基础累计交给数据库,分级规则交给配置表或代码判断。










