CUME_DIST计算逻辑是(小于等于当前值的行数)/窗口总行数,结果反映分位覆盖度而非排名百分比;其值由ORDER BY决定,NULL默认排最前,并列值共享相同结果。

什么是CUME_DIST的计算逻辑
CUME_DIST返回当前行在窗口中的「小于等于当前值的行数占比」,不是按顺序编号再除以总数,而是严格按值分组统计。比如三行值都是100,它们的CUME_DIST相同,且等于这三行最末位置在整个窗口中的比例。
公式是:(number of rows with values ≤ current row's value) / (total number of rows in window)。注意分母固定为窗口总行数,分子包含所有并列值。
CUME_DIST和PERCENT_RANK的区别在哪
两者都输出 0~1 区间值,但算法完全不同:
-
PERCENT_RANK基于排名:用(rank - 1) / (total_rows - 1),首行必为0,末行必为1(除非只有一行) -
CUME_DIST基于频次:并列值共享同一结果,末行不一定为1——只有最大值只出现一次时才等于1 - 当数据无重复且升序排列时,
CUME_DIST结果为1/n, 2/n, ..., n/n;而PERCENT_RANK是0, 1/(n-1), ..., 1
ORDER BY对CUME_DIST结果的影响
CUME_DIST必须搭配ORDER BY,否则报错(如 PostgreSQL 报window function requires an ORDER BY clause)。它只认ORDER BY表达式,不关心是否在SELECT中出现。
常见误区:
- 写成
ORDER BY id但真正想按score分布?结果会按id排序计算,完全偏离业务意图 -
ORDER BY score DESC时,CUME_DIST反映的是「大于等于当前score的比例」,容易误读为「前多少百分比」 - 多列排序如
ORDER BY dept, salary,比较逻辑是先按部门分组内排序,再累计——但CUME_DIST仍作用于整个窗口,不是每个部门独立计算
实际查数据时怎么避免理解偏差
直接看结果不如加一列辅助验证。例如:
SELECT score, COUNT(*) OVER (PARTITION BY score) AS cnt_same_score, CUME_DIST() OVER (ORDER BY score) AS cume_dist FROM exam_scores;
这样能对照看出:某score值有 3 行,它们cume_dist一致,且该值 =(前面所有≤它的行数)/ 总行数。
特别注意边界情况:
- 空值(
NULL)默认排在最前(ORDER BY ... ASC时),所以如果score有NULL,第一行CUME_DIST可能是3/10(3个NULL),而不是1/10 - 不同数据库对
NULL排序策略可配置(如NULLS LAST),PostgreSQL 和 Oracle 支持,MySQL 不支持,会影响结果
并列值多、空值存在、排序方向反直觉——这三个点最容易导致业务同学把CUME_DIST当成「排名百分比」来用,其实它更接近「分位覆盖度」。

















