在进行数据排名分析时,我们经常需要了解某一行数据在整个数据集中的相对位置,而不仅仅是它在排序列表中的绝对次序。PERCENT_RANK() 和 CUME_DIST() 作为 SQL 窗口函数中的两个重要成员,分别从百分比排名和累积分布的角度提供了这种相对位置信息。它们虽然是 SQL 标准函数,但很多开发者对它们的具体差异和应用场景仍存在困惑。下面我们就来详细解析这两个函数的概念、语法,并通过实际例子展示它们在排名分析中的威力。

函数基础概念与语法
这两个函数都属于窗口函数,需要结合 OVER() 子句使用,并且通常需要配合 ORDER BY 来指定排序依据。
PERCENT_RANK()
此函数返回某一行在分区内的相对排名,计算公式为:(rank - 1) / (total_rows - 1)。其中 rank 是该行的 RANK() 值(相同值并列排名),total_rows 是分区内的总行数。返回结果的范围是 0 到 1 之间,包括 0 和 1。排名第一的行总是 0,最后一行总是 1(如果总行数大于 1)。
PERCENT_RANK() OVER (
[PARTITION BY partition_expression]
ORDER BY sort_expression
)
CUME_DIST()
该函数计算某一行在分区内的累积分布,即严格小于等于当前值的行数占总行数的比例。计算公式为:count(rows <= current_value) / total_rows。返回结果范围也是 0 到 1 之间,且最后一行的值一定为 1。注意它与 PERCENT_RANK 的区别:相同值会得到相同的 CUME_DIST,但计算基数不同。
CUME_DIST() OVER (
[PARTITION BY partition_expression]
ORDER BY sort_expression
)
核心区别对比
为了直观理解两者的差异,我们用一个简单的 5 行数据(假设没有并列)来对比:
| 值 | RANK() | PERCENT_RANK() | CUME_DIST() |
|---|---|---|---|
| 10 | 1 | 0.00 | 0.20 |
| 20 | 2 | 0.25 | 0.40 |
| 30 | 3 | 0.50 | 0.60 |
| 40 | 4 | 0.75 | 0.80 |
| 50 | 5 | 1.00 | 1.00 |
可以看到,PERCENT_RANK 的第一行永远是 0,最后一行永远是 1;而 CUME_DIST 的第一行则取决于行数(这里是 1/5=0.2),最后一行始终为 1。两者虽然取值范围相同,但语义不同:PERCENT_RANK 强调的是排名的百分比位置(比当前排名低的比例),而 CUME_DIST 强调的是累积概率(小于等于当前值的比例)。
实际应用场景
下面通过两个典型的业务场景来演示这两个函数如何使用。
场景一:学生考试成绩排名分析
假设我们有一个成绩表 exam_scores,包含学生姓名和分数。我们希望了解每个学生的成绩在整个年级中的相对位置,既要知道他的百分比排名,也要知道有多少比例的学生成绩小于等于他。
-- 建表及插入测试数据
CREATE TABLE exam_scores (
id INTEGER PRIMARY KEY,
student_name VARCHAR(50),
score DECIMAL(5,2)
);
INSERT INTO exam_scores VALUES
(1, '张三', 92),
(2, '李四', 85),
(3, '王五', 78),
(4, '赵六', 96),
(5, '陈七', 88),
(6, '周八', 91),
(7, '吴九', 73),
(8, '郑十', 99);
现在查询每个学生的成绩、RANK、PERCENT_RANK 和 CUME_DIST:
SELECT
student_name,
score,
RANK() OVER (ORDER BY score DESC) AS rk,
PERCENT_RANK() OVER (ORDER BY score DESC) AS pct_rank,
CUME_DIST() OVER (ORDER BY score DESC) AS cume_dist
FROM exam_scores
ORDER BY score DESC;
查询结果示例(基于上述数据):
student_name | score | rk | pct_rank | cume_dist -------------+-------+----+---------------+----------- 郑十 | 99 | 1 | 0.000000 | 0.125000 赵六 | 96 | 2 | 0.142857 | 0.250000 张三 | 92 | 3 | 0.285714 | 0.375000 周八 | 91 | 4 | 0.428571 | 0.500000 陈七 | 88 | 5 | 0.571429 | 0.625000 李四 | 85 | 6 | 0.714286 | 0.750000 王五 | 78 | 7 | 0.857143 | 0.875000 吴九 | 73 | 8 | 1.000000 | 1.000000
解释一下:张三成绩 92 分,排名第 3(并列时会有变化,此处无并列)。PCT_RANK 为 0.285714,表示大约 28.6% 的人排名比他低(不包括他自己);CUME_DIST 为 0.375,表示有 37.5% 的人成绩小于等于 92 分。两个值不同,反映的含义也不同。
场景二:销售业绩分部门排名
如果我们按部门分区,想了解每个销售代表的业绩在其部门内的相对位置。使用 PARTITION BY 子句即可。
CREATE TABLE sales (
emp_id INT,
dept_id INT,
amount DECIMAL(10,2)
);
INSERT INTO sales VALUES
(101, 1, 15000),
(102, 1, 22000),
(103, 1, 18000),
(201, 2, 25000),
(202, 2, 20000),
(203, 2, 23000),
(204, 2, 21000);
SELECT
dept_id,
emp_id,
amount,
PERCENT_RANK() OVER (PARTITION BY dept_id ORDER BY amount DESC) AS dept_pct_rank,
CUME_DIST() OVER (PARTITION BY dept_id ORDER BY amount DESC) AS dept_cume_dist
FROM sales
ORDER BY dept_id, amount DESC;
结果为我们揭示了每个部门内部业绩的百分比排名和累积分布情况,便于管理者识别绩优员工和需改进员工。
注意事项与常见误区
- 并列值的处理:两个函数对并列值的处理都基于 RANK 函数。PERCENT_RANK 会跳过排名间隙,而 CUME_DIST 对并列行赋予相同的累积概率值。例如,如果有两个并列第一名,PERCENT_RANK 会计算为 0,而 CUME_DIST 为 2/总行数。
- 空值处理:默认情况下,ORDER BY 中的空值会被视为最大值或最小值(依据数据库具体实现)。建议在使用前明确处理空值,或在查询中加入
NULLS LAST等子句。 - 性能:窗口函数需要对分区内数据排序,大量数据时可能影响性能。但相比手动计算排名再算比例,SQL 窗口函数更高效也更简洁。
- 不要混淆两者:在进行分位数划分时,通常使用 NTILE 函数而非 PERCENT_RANK;而 CUME_DIST 更适合用于累积分布图或统计检验。
总结
PERCENT_RANK() 和 CUME_DIST() 是 SQL 排名分析中非常实用的窗口函数。前者告诉你某个值在排序中的百分比排名(基于排名位置),后者告诉你小于等于该值的比例(基于行数累计)。理解它们的计算逻辑和语义差异,能够帮助你在数据探索、报表制作、统计学分析中做出更准确的判断。当你需要量化一个数值在群体中的相对位置时,这两个函数就是你的得力助手。
PERCENT_RANKCUME_DIST排名分析SQL窗口函数分布函数修改时间:2026-06-08 20:18:42