percent_rank函数返回当前行在分组内的相对位置,计算公式为(rank - 1) / (total_rows - 1),其中rank由rank()确定,结果范围是[0,1],首行为0、末行为1。

PERCENT_RANK函数返回的是什么值
PERCENT_RANK() 不是四舍五入的百分比,也不是按组内排名除以总行数的简单比例。它计算的是「当前行在分组内的相对位置」,公式为:(rank - 1) / (total_rows - 1),其中 rank 是 RANK() 排序结果(相同值并列,跳过后续名次),total_rows 是该分组的总行数。
这意味着:
- 组内第一行永远是
0(因为rank = 1→(1-1)/(n-1) = 0) - 组内最后一行永远是
1(无论是否并列,只要它是排序后最后一个位置) - 如果组内只有 1 行,
PERCENT_RANK()返回0(Oracle 将分母视为 0 时定义为 0,不是报错)
必须搭配ORDER BY和PARTITION BY使用
单独写 PERCENT_RANK() 会报错 ORA-30485: missing ORDER BY expression in the window specification。它属于窗口函数,语法强制要求 ORDER BY,而 PARTITION BY 决定「按什么分组算百分比」——不写就是全表当一个组。
常见误用:
- 只写
PARTITION BY dept_id却漏掉ORDER BY salary DESC→ 报错 - 写成
ORDER BY dept_id(分区字段重复排序)→ 逻辑混乱,排名失去业务意义 - 忘记
PARTITION BY,想按部门算各自百分比,结果全公司一起排 → 数值完全失真
正确写法示例:
SELECT dept_id, emp_name, salary,
PERCENT_RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS prk
FROM employees;
与RANK、DENSE_RANK、CUME_DIST的区别在哪
容易混淆的是这几个排名函数都处理并列,但百分比逻辑不同:
-
RANK()并列时名次相同,后续跳号(如 1,1,3);PERCENT_RANK()基于此计算,所以并列项得到相同百分比值 -
DENSE_RANK()并列不跳号(1,1,2),但PERCENT_RANK()不基于它,不能混用 -
CUME_DIST()计算的是「≤当前行值的行数占比」,公式为number of rows ≤ current row / total rows,所以它的最小值不一定是 0,最大值恒为 1
举例:某部门 4 人薪资为 [10k, 15k, 15k, 20k]
-
RANK()得到 [1,2,2,4] →PERCENT_RANK()是 [0, 0.33, 0.33, 1] -
CUME_DIST()得到 [0.25, 0.75, 0.75, 1](前两个 ≤15k 的占 3/4)
实际分析中要注意NULL和排序方向
PERCENT_RANK() 对 NULL 的处理取决于 ORDER BY 中的 NULLS FIRST/LAST 设置。Oracle 默认 NULLS LAST(升序时排末尾,降序时也排末尾),这可能导致你预期外的百分比分布。
- 若薪资字段有
NULL,且你用ORDER BY salary DESC,则NULL会出现在最前面 → 它的PERCENT_RANK()是0,但业务上可能不该参与排名 - 解决方法:显式过滤或用
NULLS LAST强制排除干扰,例如ORDER BY salary DESC NULLS LAST - 降序(
DESC)下高值排前,百分比低;升序(ASC)则相反——别凭直觉猜方向,看ORDER BY实际效果
真正难的不是写对语法,而是确认业务语义:你想要“高于多少比例的人”,还是“被多少比例的人超过”——这直接决定排序方向和是否需要反转结果。











