CUME_DIST是SQL窗口函数,返回当前行在分区内“小于等于其值的行数占总行数的比例”,结果范围为(0,1],相同值行获得相同比例,必须配合OVER(ORDER BY ...)使用。

什么是 CUME_DIST,它返回什么值?
CUME_DIST 返回当前行在排序后结果集中的**相对位置比例**,即“有多少比例的行小于等于当前行”。它的值范围是 (0, 1],最小值大于 0(因为至少包含自身),最大值为 1(最后一行或并列最大值的行)。
关键点:它基于 ORDER BY 子句排序,且**自动包含重复值的影响**——相同排序值的所有行获得相同的 CUME_DIST 值,该值等于这些行中最后一行的排名除以总行数。
常见误解:它不是“当前行排名 / 总行数”,而是“≤当前行值的行数 / 总行数”。
CUME_DIST 必须配合 OVER 子句使用
它不能单独写在 SELECT 列表里,必须嵌套在 OVER() 中,否则会报错:ERROR: window function CUME_DIST requires a window definition。
实操建议:
-
OVER(ORDER BY score DESC)—— 按分数降序计算累计分布(高分占比小) -
OVER(ORDER BY score ASC)—— 升序时,低分排前面,CUME_DIST值更小 - 不能省略
ORDER BY;不支持PARTITION BY后直接省略ORDER BY - 如果想按组内计算(如每科成绩独立算分布),必须写成
OVER(PARTITION BY subject ORDER BY score)
和 PERCENT_RANK 的区别在哪?
两者都反映排序位置,但逻辑不同:
CUME_DIST 关注“≤当前值的行数占比”,而 PERCENT_RANK 关注“当前行排名减 1 后占(总行数减 1)的比例”,公式是 (rank - 1) / (total_rows - 1),首行恒为 0,末行恒为 1(即使有重复值)。
示例(3 行数据,分数为 [85, 92, 92]):
score | CUME_DIST | PERCENT_RANK 85 | 0.333... | 0.0 92 | 1.0 | 0.5 92 | 1.0 | 0.5
注意:CUME_DIST 对重复值更“保守”——两个 92 都拉到 100%,而 PERCENT_RANK 把它们平分中间段。
实际查询中容易漏掉的兼容性细节
PostgreSQL、SQL Server、Oracle、Snowflake 都支持 CUME_DIST,但 MySQL 直到 8.0.2 才引入窗口函数,且早期版本不支持;SQLite 不支持。
性能提示:
- 大表上用
CUME_DIST会触发全排序,无法利用普通索引加速ORDER BY(除非该字段有对应排序索引) - 若只关心 Top N 的累计分布,可先
LIMIT再算,但注意:OVER子句作用于整个结果集,LIMIT在窗口函数之后执行,所以必须用子查询或 CTE 提前截断 - 浮点精度问题:结果是
double precision,比较时避免用= 0.5,改用BETWEEN或容差判断
真正麻烦的是理解它怎么处理并列——很多人调完发现“为什么两个最高分都显示 1.0?”不是 bug,是设计如此。

















