CUME_DIST返回当前行在分组内“≤其值的行数占比”,范围(0,1]且相同值结果相同;PERCENT_RANK按(rank−1)/(n−1)计算,首行为0,相同值共享rank但结果恒为同一值。

什么是 CUME_DIST,它和 PERCENT_RANK 有什么区别
CUME_DIST 返回当前行在分组内的「小于等于当前值的行数占比」,结果范围是 (0, 1],且相同值必然得到相同结果。它不依赖排序位置差值,而是直接统计频次比例。PERCENT_RANK 则基于排名公式((rank-1)/(n-1)),最小值恒为 0,相同值会共享一个排名但结果仍可能不同。
举个例子:5 名员工绩效分数为 [80, 85, 85, 90, 95],按升序排列后:
-
CUME_DIST对两个 85 分都返回3/5 = 0.6(因为 ≤85 的有 3 行) -
PERCENT_RANK对两个 85 分都返回(2-1)/(5-1) = 0.25(因它们共用 rank=2)
怎么写基础语法才能让 CUME_DIST 正确工作
必须配合 ORDER BY 使用,且不能单独出现在 SELECT 列表中(即不能省略 OVER 子句)。常见错误是漏掉括号或误加 PARTITION BY 导致逻辑偏差。
正确写法示例(计算全员绩效累积分布):
SELECT name, score, CUME_DIST() OVER (ORDER BY score ASC) AS cume_dist FROM employees;
关键点:
-
CUME_DIST()后面必须跟空括号,不能传参 -
ORDER BY决定累积方向:升序(ASC)从低分到高分累积;降序(DESC)则高分先占更大比例 - 若想按部门分别计算,才加
PARTITION BY dept,否则默认全表一并计算
遇到 NULL 值时 CUME_DIST 怎么处理
NULL 默认排在最前面(ORDER BY ... ASC 时),所以第一个 CUME_DIST 值往往就是 1.0(如果只有 1 行是 NULL),容易误导你认为“最低分占比 100%”。这不是 bug,是 SQL 标准行为。
应对建议:
- 显式控制 NULL 排序:
ORDER BY score ASC NULLS LAST(PostgreSQL / Oracle 支持);MySQL 8.0+ 和 SQL Server 需用COALESCE(score, -9999)临时替换 - 业务上明确是否应排除 NULL:
WHERE score IS NOT NULL比在窗口函数里硬扛更清晰 - 注意:SQL Server 不支持
NULLS FIRST/LAST,必须用表达式绕过
为什么结果看起来“不连续”或小数位数怪怪的
CUME_DIST 返回的是精确分数(如 2/7),但数据库显示精度取决于数值类型实现。例如 PostgreSQL 返回 numeric,而 MySQL 可能截断为 double,导致 0.2857142857 显示成 0.2857。
实操建议:
- 需要固定小数位时,统一用
ROUND(CUME_DIST() OVER (...), 4) - 避免在 WHERE 或 JOIN 中直接比较浮点结果(如
cume_dist > 0.9),改用 >= 或 - 如果要取前 10%,别写
cume_dist > 0.9,而应cume_dist >= 0.9—— 因为CUME_DIST是「≤当前值」的比例,0.9 对应的是刚好覆盖 90% 的那个临界点
真正麻烦的是跨数据库兼容性:SQLite 不支持窗口函数,MySQL 在 8.0 前也不支持,用之前务必确认版本。

















