rank/row_number() OVER ()使用

本文详细解析了SQL中的row_number(), rank(), dense_rank(), lag()等排序与行号计算函数的用法及区别,通过多个SQL语句实例展示了如何在不同场景下灵活运用这些函数解决排序和分组问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

row_number() OVER (PARTITION BY COL1 ORDER BY COL2) 表示根据COL1分组,在分组内部根据 COL2排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内连续的唯一的).

  与rownum的区别在于:使用rownum进行排序的时候是先对结果集加入伪列rownum然后再进行排序,而此函数在包含排序从句后是先排序再计算行号码.

  row_number()和rownum差不多,功能更强一点(可以在各个分组内从1开时排序).

  rank()是跳跃排序,有两个第二名时接下来就是第四名(同样是在各个分组内).

  dense_rank()l是连续排序,有两个第二名时仍然跟着第三名。相比之下row_number是没有重复值的 .

  lag(arg1,arg2,arg3):
arg1是从其他行返回的表达式
arg2是希望检索的当前行分区的偏移量。是一个正的偏移量,时一个往回检索以前的行的数目。
arg3是在arg2表示的数目超出了分组的范围时返回的值。

看几个SQL语句:

语句一:

select row_number() over(order by sale/cnt desc) as sort, sale/cnt 
from (
select -60 as sale,3 as cnt from dual union 
select 24 as sale,6 as cnt from dual union 
select 50 as sale,5 as cnt from dual union 
select -20 as sale,2 as cnt from dual union 
select 40 as sale,8 as cnt from dual);


--执行结果:

          SORT       SALE/CNT
---------- ----------
             1             10
             2              5
             3              4
             4            -10
             5            -20

语句二:查询员工的工资,按部门排序

select ename,sal,row_number() over (partition by deptno order by sal desc) as sal_order from scott.emp;

--执行结果:

ENAME                           SAL      SAL_ORDER
-------------------- ---------- ----------
KING                           5000              1
CLARK                          2450              2
MILLER                         1300              3
SCOTT                          3000              1
FORD                           3000              2
JONES                          2975              3
ADAMS                          1100              4
SMITH                           800              5
BLAKE                          2850              1
ALLEN                          1600              2
TURNER                         1500              3
WARD                           1250              4
MARTIN                         1250              5
JAMES                           950              6

已选择14行。


语句三:查询每个部门的最高工资

select deptno,ename,sal from 
     (select deptno,ename,sal,row_number() over (partition by deptno order by sal desc) as sal_order 
         from scott.emp) where sal_order <2;

--执行结果:

       DEPTNO ENAME                          SAL
---------- -------------------- ----------
           10 KING                          5000
           20 SCOTT                         3000
           30 BLAKE                         2850

已选择3行。


语句四:

select deptno,sal,rank() over (partition by deptno order by sal) as rank_order from scott.emp order by deptno;

--执行结果:

     DEPTNO         SAL RANK_ORDER
---------- ---------- ----------
         10        1300           1
         10        2450           2
         10        5000           3
         20         800           1
         20        1100           2
         20        2975           3
         20        3000           4
         20        3000           4
         30         950           1
         30        1250           2
         30        1250           2
         30        1500           4
         30        1600           5
         30        2850           6

已选择14行。


语句五:

select deptno,sal,dense_rank() over(partition by deptno order by sal) as dense_rank_order from scott.emp order by deptn; 

执行结果:

     DEPTNO         SAL DENSE_RANK_ORDER
---------- ---------- ----------------
         10        1300                 1
         10        2450                 2
         10        5000                 3
         20         800                 1
         20        1100                 2
         20        2975                 3
         20        3000                 4
         20        3000                 4
         30         950                 1
         30        1250                 2
         30        1250                 2
         30        1500                 3
         30        1600                 4
         30        2850                 5

已选择14行。


语句六:

select deptno,ename,sal,lag(ename,1,null) over(partition by deptno order by ename) as lag_ from scott.emp order by deptno;

执行结果:



     DEPTNO ENAME                        SAL LAG_
---------- -------------------- ---------- --------------------
         10 CLARK                       2450
         10 KING                        5000 CLARK
         10 MILLER                      1300 KING
         20 ADAMS                       1100
         20 FORD                        3000 ADAMS
         20 JONES                       2975 FORD
         20 SCOTT                       3000 JONES
         20 SMITH                        800 SCOTT
         30 ALLEN                       1600
         30 BLAKE                       2850 ALLEN
         30 JAMES                        950 BLAKE
         30 MARTIN                      1250 JAMES
         30 TURNER                      1500 MARTIN
         30 WARD                        1250 TURNER

已选择14行。


 

<think>好的,我现在需要回答用户关于SQL中ROW_NUMBERRANKDENSE_RANK函数的区别及用法的问题。首先,我得回忆一下这三个窗口函数的基本概念它们的不同之处。 用户提供的引用材料里已经给出了一些关键点。引用[1]提到ROW_NUMBER()会给每一行唯一的序号,而RANKDENSE_RANK在遇到相同值时会有不同的处理方式。引用[2]中的示例展示了具体的数据排名结果,这对理解差异很有帮助。比如,当两个员工的薪水相同时,RANK会跳过后续的排名,而DENSE_RANK不会跳过。引用[3][4]进一步解释了这些函数的适用场景,比如RANK适用于有并列但后续排名跳过的需求,而DENSE_RANK则保持连续排名。 接下来,我需要整理这些信息,确保回答的结构清晰。可能需要先分别介绍每个函数的特点,然后对比它们的区别,再通过示例说明。用户可能需要知道何时使用哪个函数,所以实际应用场景也很重要。 需要注意的是,用户可能对窗口函数的OVER子句不太熟悉,所以可能需要简要提到用法,比如ORDER BY子句的必要性。同时,示例的展示应该简单明了,直接使用用户提供的例子或者稍作调整,以帮助理解。 另外,用户问题中的引用材料提到NTILE函数,但用户并未询问,所以可以暂时忽略。重点放在三个函数的对比上。要确保回答准确,比如ROW_NUMBER是否绝对唯一,即使数据相同;RANK在相同值后的处理方式;DENSE_RANK如何处理相同排名后的下一个排名。 最后,生成相关问题时要围绕这三个函数的区别使用场景、性能考虑等方面提问,帮助用户深入理解。</think>### SQL中ROW_NUMBERRANK、DENSE_RANK区别及用法 #### 一、核心区别 1. **ROW_NUMBER()** 为每一行生成**唯一且连续的序号**,即使数据完全相同也会分配不同序号。例如: $$ \text{数据:[100, 100, 90] → 排名:[1, 2, 3]} $$ 2. **RANK()** 允许重复值共享相同排名,但会**跳过后续序号**。例如: $$ \text{数据:[100, 100, 90] → 排名:[1, 1, 3]} $$ 3. **DENSE_RANK()** 允许重复值共享相同排名,且**后续序号保持连续不跳过**。例如: $$ \text{数据:[100, 100, 90] → 排名:[1, 1, 2]} $$ #### 二、语法与示例 所有函数均需配合`OVER (ORDER BY ...)`使用: ```sql SELECT id, salary, ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num, RANK() OVER (ORDER BY salary DESC) AS rank, DENSE_RANK() OVER (ORDER BY salary DESC) AS dense_rank FROM employees; ``` **示例结果**(引用自用户提供的资料[^2]): | id | name | salary | row_num | rank | dense_rank | |----|--------|--------|---------|------|------------| | 4 | David | 80000 | 1 | 1 | 1 | | 2 | Bob | 70000 | 2 | 2 | 2 | | 3 | Charlie| 70000 | 3 | 2 | 2 | | 1 | Alice | 60000 | 4 | 4 | 3 | | 5 | Eve | 50000 | 5 | 5 | 4 | #### 三、使用场景 1. **ROW_NUMBER**:需强制生成唯一序号时(如分页、去重)[^3] 2. **RANK**:允许并列但需反映实际位置(如体育比赛排名)[^4] 3. **DENSE_RANK**:需连续排名且不跳号(如成绩等级划分)[^4] #### 四、性能注意事项 - 所有窗口函数在大型数据集上可能影响性能,建议配合索引使用 - 分区子句`PARTITION BY`可针对分组独立计算排名(如部门内排名)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值