介绍
下面3个函数 搭配 over (PARTITION by ... order by ...) 使用
row_number():为每行增加一个序号,同一分区中,序号从1开始,下一行增加1rank():与row_number()相同,但是,当order by值相同时,序号相同,但会占用下一行的序号dense_rank():与row_number()相同,但是,当order by值相同时,序号相同,不会 占用下一行的序号
应用场景
查询统计 TopN
如:
- 查询工资最高的前3名员工
- 销量最多的10件商品
- 查询成绩最高的前3名学生(并列第一,不占用第二、第三的名额)
例子
SQL
根据 depnot 分区,每个区内根据 sal 进行排序
select deptno,ename,sal,
row_number() over( PARTITION by deptno order by sal desc) as row_num,
rank() over (PARTITION by deptno order by sal desc) as rnk,
dense_rank() over (PARTITION by deptno order by sal desc) as dns_rnk
from emp
执行结果如下:
解释:
根据 depnot 分区,每个区内根据 sal 进行排序
row_number():不论sal是多少,都逐行递增序号rank():当sal相同时, 序号相同,但会占用下一行序号dense_rank():当sal相同时, 序号相同,不会 占用下一行序号
要搭配 order by 使用
如果不加 order by ...,如下:
select deptno,ename,sal,
row_number() over( PARTITION by deptno ) as row_num,
rank() over (PARTITION by deptno ) as rnk,
dense_rank() over (PARTITION by deptno ) as dns_rnk
from emp
执行如下图:
- row_num:分区内序号 不知道 是根据哪一列排序的
- rnk、dns_rnk:序号都是1,没有意义
案例
查询统计每个部门 工资 最高的 2名 员工的部门编号、姓名、工资(每个部门 只要前2名)
分析
根据 deptno 分区,根据 sal 倒序排序,由于 每个部门只要2名,所以取 row_number()
row_number() 实现
with tbl as (
select deptno,ename,sal,
row_number() over (PARTITION by deptno order by sal desc) as row_num
from emp
)
select deptno,ename,sal from tbl where row_num<=2
执行结果:
| deptno | ename | sal | row_num |
|---|---|---|---|
| 10 | KING | 5000.0 | 1 |
| 10 | CLARK | 2450.0 | 2 |
| 20 | SCOTT | 3000.0 | 1 |
| 20 | FORD | 3000.0 | 2 |
| 30 | BLAKE | 2850.0 | 1 |
| 30 | ALLEN | 1600.0 | 2 |
注意: 部门编号是 20 的,前 2名 员工工资相同,使用 row_number() 仍排序 1、2
rank()实现
with tbl as (
select deptno,ename,sal,rank() over( PARTITION by deptno order by sal desc) as rk from emp
)
select * from tbl where rk<=2
执行结果:
| deptno | ename | sal | rk |
|---|---|---|---|
| 10 | KING | 5000.0 | 1 |
| 10 | CLARK | 2450.0 | 2 |
| 20 | SCOTT | 3000.0 | 1 |
| 20 | FORD | 3000.0 | 1 |
| 30 | BLAKE | 2850.0 | 1 |
| 30 | ALLEN | 1600.0 | 2 |
特点:使用 rank() 实现,可知道 deptno是 20的,SCOTT、FORD 是 并列第一,这是 row_number() 不具备的功能
案例2
查询统计每个部门 工资 最高的 2名 员工的部门编号、姓名、工资(工资相同的,不多占用名额)
类似名次,并列第一的,不会占用第二、第三的名额
分析
根据 deptno 分区,根据 sal 倒序排序,由于 工资相同的,不多占用名额,所以取 dense_rank()
SQL
with tbl as (
select deptno,ename,sal,
dense_rank() over (PARTITION by deptno order by sal desc) as dns_rnk
from emp
)
select deptno,ename,sal from tbl where dns_rnk<=2
执行结果:
| deptno | ename | sal | dns_rnk |
|---|---|---|---|
| 10 | KING | 5000.0 | 1 |
| 10 | CLARK | 2450.0 | 2 |
| 20 | SCOTT | 3000.0 | 1 |
| 20 | FORD | 3000.0 | 1 |
| 20 | JONES | 2975.0 | 2 |
| 30 | BLAKE | 2850.0 | 1 |
| 30 | ALLEN | 1600.0 | 2 |
注意: 部门编号是 20 的,前 2名 员工工资相同,不占用名额,所以会查出 JONES

