在SQL查询中,对分组后的数据做排名是常见需求,比如统计每个部门内员工的绩效排名、每个品类下商品的销量排名等,RANK和DENSE_RANK作为窗口函数,能够高效实现这类分组排名需求。

RANK与DENSE_RANK的基本语法
两个函数都属于窗口函数的范畴,基本语法结构一致,都需要配合OVER子句使用,OVER子句中可以指定分组规则PARTITION BY和排序规则ORDER BY。
语法格式如下:
-- RANK函数语法 RANK() OVER (PARTITION BY 分组字段 ORDER BY 排序字段 [ASC|DESC]) -- DENSE_RANK函数语法 DENSE_RANK() OVER (PARTITION BY 分组字段 ORDER BY 排序字段 [ASC|DESC])
其中PARTITION BY用来指定分组的字段,也就是按照哪个字段将数据分成不同的组,每个组内的排名相互独立;ORDER BY用来指定组内排序的字段和排序方向,ASC是升序,DESC是降序。
两者的核心差异
RANK和DENSE_RANK的核心区别在于对并列排名的处理规则不同,具体差异如下:
| 函数名称 | 并列排名处理规则 | 后续排名数值 |
|---|---|---|
| RANK | 相同数值的排名相同,会占用排名位次 | 并列排名数量+当前排名数值 |
| DENSE_RANK | 相同数值的排名相同,不占用排名位次 | 当前排名数值+1 |
实际案例演示
假设我们有一张员工绩效表employee_performance,包含部门IDdept_id、员工IDemp_id、绩效分数score三个字段,现在需要统计每个部门内员工的绩效排名,分别用RANK和DENSE_RANK实现。
首先创建测试表并插入测试数据:
-- 创建员工绩效表
CREATE TABLE employee_performance (
dept_id INT,
emp_id INT,
score INT
);
-- 插入测试数据
INSERT INTO employee_performance (dept_id, emp_id, score) VALUES
(1, 101, 95),
(1, 102, 95),
(1, 103, 90),
(1, 104, 85),
(2, 201, 88),
(2, 202, 88),
(2, 203, 80),
(2, 204, 75);
使用RANK函数分组排名
查询每个部门内员工的绩效RANK排名,SQL语句如下:
SELECT
dept_id,
emp_id,
score,
RANK() OVER (PARTITION BY dept_id ORDER BY score DESC) AS rank_score
FROM employee_performance
ORDER BY dept_id, rank_score;
查询结果如下:
| dept_id | emp_id | score | rank_score |
|---|---|---|---|
| 1 | 101 | 95 | 1 |
| 1 | 102 | 95 | 1 |
| 1 | 103 | 90 | 3 |
| 1 | 104 | 85 | 4 |
| 2 | 201 | 88 | 1 |
| 2 | 202 | 88 | 1 |
| 2 | 203 | 80 | 3 |
| 2 | 204 | 75 | 4 |
可以看到部门1中两个95分的员工并列第1名,下一个90分的员工排名为3,跳过了第2名,这就是RANK函数占用排名位次的体现。
使用DENSE_RANK函数分组排名
同样的需求,使用DENSE_RANK函数实现,SQL语句如下:
SELECT
dept_id,
emp_id,
score,
DENSE_RANK() OVER (PARTITION BY dept_id ORDER BY score DESC) AS dense_rank_score
FROM employee_performance
ORDER BY dept_id, dense_rank_score;
查询结果如下:
| dept_id | emp_id | score | dense_rank_score |
|---|---|---|---|
| 1 | 101 | 95 | 1 |
| 1 | 102 | 95 | 1 |
| 1 | 103 | 90 | 2 |
| 1 | 104 | 85 | 3 |
| 2 | 201 | 88 | 1 |
| 2 | 202 | 88 | 1 |
| 2 | 203 | 80 | 2 |
| 2 | 204 | 75 | 3 |
部门1中两个95分的员工并列第1名,下一个90分的员工排名为2,没有跳过位次,这就是DENSE_RANK函数不占用排名位次的特点。
使用场景选择
在实际业务中,可以根据需求选择合适的函数:
- 如果需要排名连续,不跳过位次,比如竞赛排名中允许并列后下一个名次顺延,就选择DENSE_RANK函数。
- 如果排名需要反映并列占用的位次,比如奖学金评选中并列第一占用两个名额,下一个名次是第三名,就选择RANK函数。
另外需要注意,这两个函数都只能用在SELECT子句或者ORDER BY子句中,不能用在WHERE子句里,因为窗口函数的执行顺序在WHERE过滤之后。
SQLRANKDENSE_RANK分组排名窗口函数修改时间:2026-07-04 19:03:28