帕累托分析需先按指标降序排序再累计占比,SQL中用SUM()窗口函数实现,必须显式ORDER BY保证顺序;分组帕累托需PARTITION BY与ORDER BY并用;MySQL 8.0+应弃用变量改用窗口函数;注意并列值处理差异及索引优化。
帕累托分析的核心逻辑:先排序再累加
帕累托贡献度(即“80/20法则”量化)本质是:对分类按指标值降序排列,再计算每个分类的累计占比。SQL 本身不直接支持“窗口内累计百分比”,但可通过
窗口函数 + 总量除法实现。关键不是套公式,而是确保排序、分组、累计三者顺序无误——常见错误是漏掉
子句导致
累加无序,结果完全失真。
必须用
显式声明累加顺序,否则窗口函数默认按物理存储顺序累加
若需“每个大类下独立做帕累托”(如按
分组),则
和
都不可少
累计百分比 =
,注意分子分母都用窗口函数,且分母不能写成标量子查询(性能差且易出错)
MySQL 8.0+ 实操:避免 user-defined variable 的陷阱
MySQL 5.7 及以前常用变量(
)模拟累计,但变量执行顺序不稳定,尤其在含
或连接时极易错乱。MySQL 8.0+ 应强制使用窗口函数,这是唯一可靠方式。
是逐行累计值,不是当前行值
分母
必须不含
,否则变成“到当前行为止的总和”,而非全组总量
如果表数据量大,建议在
上建联合索引,加速
窗口计算
PostgreSQL / SQL Server:处理并列值时的累计逻辑差异
当多个分类销售值相同时(如两个商品都是 1000),MySQL 窗口函数会按任意顺序分配累计值,而 PostgreSQL 的
默认行为可能把并列值“捆在一起”累加——这反而更符合帕累托场景(相同贡献应共享同一累计位置)。
PostgreSQL 中显式写
可让并列值获得相同累计值
SQL Server 默认用
模式,与 MySQL 一致;如需并列处理,得改用
并配合
手动去重后再累计
累计百分比超过 100.0?检查是否用了
或漏了
——整数除法会导致结果截断为 0
可视化前的关键清洗:帕累托线通常只取前 N 项
真实业务中很少展示全部分类的累计线(尤其当有上千个 SKU 时),而是聚焦“贡献前 80% 的分类有哪些”。此时需在累计后加过滤,但注意:不能用
推荐用
更简洁做法:加
,再用
别忽略 NULL 值:若
允许为空,
会把 NULL 排最前,导致累计从空值开始——务必加
帕累托分析真正难的不是计算本身,而是确认“分类维度是否合理”“原始数值是否已去噪”“累计基准是否该用总和还是中位数”——这些没法靠 SQL 函数解决,得回业务现场问清楚。
SUM()ORDER BYSUM() OVER ()ORDER BY value DESCcategoryPARTITION BY categoryORDER BY value DESCROUND(100.0 * SUM(value) OVER (...) / SUM(value) OVER (), 2)@cumsum := @cumsum + valueORDER BYSELECT
category,
sales,
ROUND(100.0 * SUM(sales) OVER (PARTITION BY category ORDER BY sales DESC)
/ SUM(sales) OVER (PARTITION BY category), 2) AS cum_pct
FROM orders
ORDER BY category, cum_pct;SUM(sales) OVER (PARTITION BY category ORDER BY sales DESC)SUM(sales) OVER (PARTITION BY category)ORDER BY(category, sales)PARTITION BY + ORDER BYRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWSUM(value) OVER (ORDER BY value DESC RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)ROWSRANGEDENSE_RANK()AVG()100.0 *WHERE cum_pct ,因为累计是递增的,要找的是“首次达到或超过 80% 的那一行及其之前所有行”。SELECT * FROM (子查询) t WHERE cum_pct = 80)ROW_NUMBER() OVER (ORDER BY cum_pct)MAX(cum_pct) FILTER (WHERE cum_pct (PostgreSQL)定位拐点salesORDER BY sales DESCWHERE sales IS NOT NULL