CUME_DIST是窗口函数,返回分组内小于等于当前值的行数占比,范围(0,1],相同值共享同一比例;它基于值分布而非序号,契合“识别大客户”业务目标,但须用ORDER BY ... DESC避免结果倒置。

什么是 CUME_DIST,它和业务目标是否匹配?
CUME_DIST 返回当前行在分组内的「小于等于当前值的行数占比」,结果范围是 (0, 1],且相同值共享同一累积比例。它不依赖排序位置编号(不像 ROW_NUMBER),而是基于值的分布密度——这点正好契合「识别大客户」场景:我们关心的是「营收 ≥ 某个门槛的客户占总体多少」,而不是「第几名」。
但要注意:CUME_DIST 默认按升序计算,而大客户通常对应高营收值。若直接对 amount 使用,最高营收客户的 CUME_DIST 会是 1.0,最低的反而接近 0 —— 这和直觉相反。所以必须显式指定 ORDER BY amount DESC。
常见错误现象:
- 没写
ORDER BY ... DESC,导致结果倒置,误把小客户当核心 - 在无
PARTITION BY的情况下跨多区域混算,掩盖局部高价值客户群 - 用
CUME_DIST替代PERCENT_RANK,混淆「含自身」与「不含自身」的统计逻辑
如何用 CUME_DIST 定位前 5% 的大客户?
核心思路:先算出每个客户的 CUME_DIST(按营收降序),再筛选 CUME_DIST <= 0.05 的记录。注意不是「取前 N 行」,因为多个客户可能并列同一营收值,CUME_DIST 会把它们一并纳入。
SELECT customer_id, amount, CUME_DIST() OVER (ORDER BY amount DESC) AS cum_dist FROM orders WHERE cum_dist <= 0.05;
但上面 SQL 会报错——窗口函数不能直接在 WHERE 中引用别名。正确写法是嵌套子查询或使用 CTE:
WITH ranked AS (
SELECT
customer_id,
amount,
CUME_DIST() OVER (ORDER BY amount DESC) AS cum_dist
FROM orders
)
SELECT customer_id, amount
FROM ranked
WHERE cum_dist <= 0.05;关键细节:
-
CUME_DIST是确定性函数,不受NULL影响(默认NULLS LAST,若需调整可加NULLS FIRST) - 若客户有多个订单,应先按
customer_id聚合(如SUM(amount)),否则单笔大额订单可能扭曲客户级分布 - 数据库兼容性:PostgreSQL、SQL Server、Oracle、Snowflake 支持;MySQL 8.0+ 支持;SQLite 不支持
和 PERCENT_RANK 混用时为什么结果不同?
PERCENT_RANK 计算的是「(排名 - 1) / (总行数 - 1)」,最小值为 0,最大值趋近但不等于 1;而 CUME_DIST 是「≤ 当前行值的行数 / 总行数」,最小值 > 0(除非有 NULL 且设为 NULLS FIRST),最大值恒为 1。
例如 5 行数据,全部 amount = 100:
-
CUME_DIST全部返回1.0(所有行都 ≤ 当前行值) -
PERCENT_RANK全部返回0.0(排名都是 1,(1-1)/(5-1)=0)
所以,要识别「贡献了 95% 营收的头部客户」,必须用 CUME_DIST;若想看「某客户营收排在什么相对位置(不含自身)」,才考虑 PERCENT_RANK。
实际业务中容易被忽略的聚合粒度问题
直接对原始订单表跑 CUME_DIST 得到的「大客户」,本质是「大订单」,不是「大客户」。真正需要的是客户维度聚合后再次分布计算:
WITH cust_total AS (
SELECT
customer_id,
SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
),
cust_dist AS (
SELECT
customer_id,
total_amount,
CUME_DIST() OVER (ORDER BY total_amount DESC) AS cum_dist
FROM cust_total
)
SELECT customer_id, total_amount
FROM cust_dist
WHERE cum_dist <= 0.05;这个两层结构不可跳过。漏掉第一层 GROUP BY,会导致一个客户多笔订单被重复计数,CUME_DIST 的分母变大,稀释头部集中度,最终选出来的「前 5%」可能根本不是真实高价值客户。

















