CUME_DIST() 返回“≤当前分数的行数÷窗口总行数”,结果为(0,1]区间浮点数,需配合ORDER BY和PARTITION BY使用,不可用于WHERE过滤,展示时应乘100、四舍五入并加%符号。

直接用 CUME_DIST() 就能算,但结果不是“第几名”,而是“有多少比例 ≤ 当前分数”
很多人以为 CUME_DIST() 返回的是类似“第 2 名 / 总 100 人 = 2%”这种排名百分比,其实不是。它返回的是「小于等于当前行 score 的行数 ÷ 当前窗口总行数」,结果范围是 (0, 1],天然连续、对重复值敏感。比如 5 行数据中两个并列最高分(95),它们的 CUME_DIST() 都是 5/5 = 1.0;而两个并列 80 分(排第二梯队)若覆盖前 3 行,则都是 3/5 = 0.6。
CUME_DIST() 必须带 ORDER BY,且不能裸写在 WHERE 或子查询里
语法强制要求窗口定义包含排序,否则报错 ERROR 3589 (HY000): Window 'w' requires an ORDER BY clause。它也不能像普通函数那样直接用于过滤条件——WHERE CUME_DIST() > 0.9 是非法的。
- ✅ 正确写法:
SELECT score, CUME_DIST() OVER (ORDER BY score DESC) AS cume_pct FROM exam_results - ❌ 错误写法:
SELECT * FROM exam_results WHERE CUME_DIST() OVER (ORDER BY score) > 0.9 - ⚠️ 注意:如果想筛 Top 10%,得用派生表或 CTE,例如
SELECT * FROM (SELECT ..., CUME_DIST() OVER (...) AS p FROM t) t2 WHERE p >= 0.9
分组计算(如按班级)必须显式写 PARTITION BY,否则全是全表统计
不加 PARTITION BY 就默认整个结果集为一个窗口,所有学生混在一起排——这在跨班级场景下会严重失真。比如某班平均分低,但因全校高分集中在另一班,该班最高分可能只拿到 0.3 的 CUME_DIST(),看起来垫底,实际已是本班第一。
- ✅ 按班级算累积占比:
CUME_DIST() OVER (PARTITION BY class_id ORDER BY score DESC) - ✅ 多字段排序(先按科类再按分数):
CUME_DIST() OVER (PARTITION BY subject ORDER BY grade_level, score DESC) - ⚠️ NULL 值默认排最前(
NULLS FIRST),若分数字段有空值,会拉低整体分布——需显式写ORDER BY score DESC NULLS LAST
导出或展示时别直接贴小数,记得 ×100 + 四舍五入 + 加 % 符号
CUME_DIST() 返回的是浮点数(如 0.9999999999999999),直接转字符串拼 '%' 容易显示成 "99.99999999999999%",业务报表里根本没法看。
- ✅ 推荐处理:
CONCAT(ROUND(cume_pct * 100, 2), '%') - ⚠️ 别用
CAST(cume_pct * 100 AS SIGNED),会砍掉小数,多个不同名次变成相同百分比(如 0.94 和 0.96 全变 94%) - ⚠️
ROUND()在 MySQL 中对浮点精度有影响,大数据量下建议先用DECIMAL类型存储中间结果,或在应用层做格式化
真正容易被忽略的是:同一分数横跨多个分组时,CUME_DIST() 在每个分组内独立计算,但人眼容易当成全局连续排位——比如两个班都有 90 分,A 班 90 分是第 1,B 班 90 分是第 3,它们的 CUME_DIST() 却都可能是 1.0 和 0.6,表面看数值差异大,实际反映的是各自班级内部结构,不是绝对高低。


















