cume_dist是窗口函数,返回当前行值在分区内的累积分布比例,即≤当前行值的行数占分区总行数的比例,结果范围为(0,1],必须配合含order by的over子句使用。

什么是 CUME_DIST,它返回什么值
CUME_DIST 是窗口函数,用于计算当前行在分区内的「累积分布比例」——即值小于等于当前行的行数占分区总行数的比例。结果范围是 (0, 1],最小值一定大于 0(哪怕排第一),最大值恒为 1(最后一组相同值也占满)。
关键点:它按 ORDER BY 排序后统计「≤ 当前行值」的累计占比,不是按行号、也不是按严格排名;相同值会得到相同的 CUME_DIST 值。
常见误用:把它当 PERCENT_RANK 用(后者是 (0, 1) 开区间,首行=0),或当成 RANK/DENSE_RANK 的变体(它们返回整数排名,不是比例)。
必须搭配 OVER() 使用,且 ORDER BY 不可省略
CUME_DIST 没有非窗口形式,不写 OVER 直接报错,比如 SELECT CUME_DIST() FROM t 会提示类似 "CUME_DIST() requires an OVER clause" 的错误。
ORDER BY 在 OVER 中是强制项,不写会报错(如 PostgreSQL 报 "window function CUME_DIST requires an ORDER BY clause")。即使你想按整个表算全局分布,也要显式写 ORDER BY some_col —— 不能靠默认顺序。
- 支持多列排序:
OVER (ORDER BY dept ASC, salary DESC) - 可加
PARTITION BY分组计算:OVER (PARTITION BY dept ORDER BY salary),此时每个部门独立算累积比例 - 不支持
ROWS BETWEEN等帧子句 ——CUME_DIST总是基于整个分区计算,无法限制“前3行”之类
和 PERCENT_RANK 的数值差异很实际
两者都返回比例,但算法不同,导致结果明显不同,尤其在首尾和重复值处:
-
CUME_DIST= (≤ 当前行值的行数) / (分区总行数) → 首行 > 0,末行 = 1 -
PERCENT_RANK= (排名 - 1) / (总行数 - 1) → 首行 = 0,末行 = 1(仅当无并列时)
例如 5 行数据,值全为 100:CUME_DIST 全是 1.0(因为每行都满足 “≤ 当前行值” 的行数 = 5);PERCENT_RANK 全是 0.0(因所有行 RANK = 1,所以 (1−1)/(5−1) = 0)。
再如值为 [10,20,20,30]:CUME_DIST 结果是 [0.25, 0.75, 0.75, 1.0](≤20 的有 3 行 → 3/4 = 0.75);PERCENT_RANK 是 [0.0, 0.33, 0.33, 1.0](第二三行 RANK = 2 → (2−1)/(4−1) ≈ 0.33)。
实际分析场景中要注意 NULL 和排序方向
NULL 默认排在最前(ORDER BY col ASC 时),所以如果字段含 NULL,第一行的 CUME_DIST 可能远高于预期(比如 10% 行是 NULL,那第一组 NULL 的累积比例就是 0.1)。
- 想把
NULL排最后?显式写ORDER BY col ASC NULLS LAST(PostgreSQL/Oracle 支持;MySQL 8.0+ 用IS NULL判断模拟) - 业务上常需过滤
NULL再算分布,避免扭曲比例:加WHERE col IS NOT NULL - 升序(
ASC)对应「从低到高」的累积,降序(DESC)则变成「从高到低」累积 —— 比如分析高分占比,用ORDER BY score DESC更直观
真正容易被忽略的是:累积分布的意义高度依赖排序语义。写 ORDER BY created_at 算的是时间维度的渗透率,而 ORDER BY amount 算的是金额维度的覆盖度——选错排序字段,整个分析就偏了。










