帕累托分析需先按指标降序排序再累计占比,SQL中用SUM()窗口函数实现,必须显式ORDER BY保证顺序;分组帕累托需PARTITION BY与ORDER BY并用;MySQL 8.0+应弃用变量改用窗口函数;注意并列值处理差异及索引优化。

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

















