CUME_DIST()是累积分布函数,返回“小于等于当前值的行数÷分组总行数”,结果范围为(0,1];它反映某值在组内的相对位置下界(如0.75表示≥75%的数据),但不插值、不支持指定百分位点,不能替代PERCENTILE_CONT等百分位数函数。

什么是 CUME_DIST(),它和百分位数的关系是什么?
CUME_DIST() 返回当前行在分组内的累积分布值,即“小于等于当前值的行数 ÷ 分组总行数”。它的结果范围是 (0, 1],且严格递增(相同值共享同一 CUME_DIST() 值)。它不是直接计算任意百分位数(如 PERCENTILE_CONT),但能告诉你某一行“排在前百分之几”——比如 CUME_DIST() = 0.75 意味着该行值 ≥ 75% 的同组数据。
注意:它不插值,也不支持指定百分位点(如第90百分位),只对当前排序位置给出相对位置。
CUME_DIST() 必须配合 OVER() 子句使用
没有 OVER(),CUME_DIST() 会报错(如 PostgreSQL 报 window function call requires window definition,SQL Server 报 Incorrect syntax near ')')。
必须明确指定:
-
ORDER BY:决定累积顺序(不可省略) - 可选
PARTITION BY:定义分组边界(不写则全表视为一个组)
SELECT score, CUME_DIST() OVER (PARTITION BY subject ORDER BY score) AS cume_dist FROM exam_scores;
如果漏掉 ORDER BY,MySQL 8.0+ 和 PostgreSQL 都会拒绝执行;SQL Server 则直接语法错误。
相同值导致 CUME_DIST() 跳跃,不是线性增长
当多行值相同时,CUME_DIST() 会把它们视为“并列”,跳过中间值。例如某组 5 行数据按 score 排序为 [80, 85, 85, 85, 92],其 CUME_DIST() 结果是:
- 80 → 0.2(1/5)
- 85 → 0.8(4/5,因为三个 85 占据第2–4位,累计到第4行)
- 92 → 1.0(5/5)
这说明:
- 它反映的是“
- 若需线性百分位(如每个 rank 对应唯一百分比),应改用
ROW_NUMBER()或RANK()手动计算 - 不能用
CUME_DIST()直接筛选“前10%”,因为 0.1 可能根本不出现在结果中
不同数据库对空值(NULL)的处理不一致
- PostgreSQL 和 SQL Server 默认把
NULL 排在最前(NULLS FIRST),所以 CUME_DIST() 最小值可能对应 NULL
- MySQL 8.0+ 默认
NULL 排最后(NULLS LAST)
- 如果业务要求
NULL 不参与统计,得先过滤:WHERE score IS NOT NULL,否则 CUME_DIST() 会把 NULL 算进分母和分子
NULL 排在最前(NULLS FIRST),所以 CUME_DIST() 最小值可能对应 NULL
NULL 排最后(NULLS LAST)NULL 不参与统计,得先过滤:WHERE score IS NOT NULL,否则 CUME_DIST() 会把 NULL 算进分母和分子实际写法建议显式控制:
CUME_DIST() OVER (PARTITION BY dept ORDER BY salary NULLS LAST)
否则在跨库迁移或联合查询时,同一语句在不同环境产出不同 cume_dist 值,容易引发误判。
CUME_DIST() 的核心作用是定位“某个值在组内所处的相对位置下界”,而不是生成平滑百分位刻度——这点容易被忽略,尤其当需求其实是找“第95百分位的数值”时,它完全不能替代 PERCENTILE_CONT(0.95)。

















