percent_rank 返回0到1之间的小数,因其计算公式为(rank-1)/(total_rows-1),首行恒为0.0、末行恒为1.0;单行时分母为0按标准返回0.0;必须配合order by使用,支持nulls last控制空值位置;并列时共享同一百分位值;分区计算需partition by与order by共用,且筛选前10%应使用

PERCENT_RANK 为什么返回 0 和 1 之间的小数
PERCENT_RANK 不是四舍五入的“第几名百分比”,而是基于**排名位置与总行数的关系**计算:它把当前行的排名减 1,再除以总行数减 1。公式是 (rank - 1) / (total_rows - 1)。所以第一行永远是 0.0,最后一行永远是 1.0(只要没 NULL 或 PARTITION 干扰)。如果只有一行数据,PERCENT_RANK 会返回 0.0(因为分母为 0 时 SQL 标准定义为 0)。
ORDER BY 是必须的,且不能省略 ASC/DESC
不写 ORDER BY 会导致语法错误——PERCENT_RANK 是窗口函数,必须指定排序依据。成绩越高越靠前,就用 ORDER BY score DESC;反之用 ASC。注意:NULL 默认排在最前(ASC)或最后(DESC),可能拉偏结果。若想把 NULL 当最低分处理,显式加 NULLS LAST:
SELECT name, score,
PERCENT_RANK() OVER (ORDER BY score DESC NULLS LAST) AS pct_rank
FROM students;
和 RANK、DENSE_RANK 混用时要注意“并列怎么算”
当多个学生分数相同时,RANK() 和 DENSE_RANK() 会给出相同排名(比如两个 95 分都排第 2),但 PERCENT_RANK 的分母仍是总行数减 1,分子是「该排名对应的第一行的 rank - 1」。这意味着并列者共享同一个百分位值。
- 假设 5 人成绩:100, 95, 95, 80, 70 → 总行数 = 5,分母 = 4
- 两个 95 分的
RANK都是 2 →PERCENT_RANK = (2-1)/4 = 0.25 - 而 80 分的
RANK是 4 →PERCENT_RANK = (4-1)/4 = 0.75
别指望 PERCENT_RANK 能反映“超过多少比例的人”——它反映的是“在排序序列中的相对位置”,不是累积分布。
按班级分组计算时,PARTITION BY 必须配合 ORDER BY
跨班级比较意义不大,通常要算“本班内百分位”。这时用 PARTITION BY class,但注意:每个分区独立计算,ORDER BY 也要写在窗口定义里:
SELECT class, name, score,
PERCENT_RANK() OVER (
PARTITION BY class
ORDER BY score DESC NULLS LAST
) AS pct_rank_in_class
FROM students;
漏掉 PARTITION BY 或 ORDER BY 中任意一个,结果要么全表混算,要么报错。另外,如果某班只有 1 人,他的 PERCENT_RANK 一定是 0.0——这点容易被当成 bug,其实是标准行为。
真正容易被忽略的是:百分位数值本身不带业务含义,它只是排序位置的线性映射;你要拿它做“前 10% 学生”筛选时,得用 pct_rank_in_class ,而不是 <code>——因为 <code>0.1 对应的是“排在第 11% 位置”的人,不是“前 10%”的边界。










