分析函数——排序排列(rank、dense_rank、row_number)

Oracle从8i开始就提供了3个分析函数:rank,dense_rank,row_number


(1)Rank函数返回一个唯一的值,除非遇到相同的数据时,此时所有相同数据的排名是一样的,
   同时会在最后一条相同记录和下一条不同记录的排名之间空出排名。
   
(2)Dense_rank函数返回一个唯一的值,除非当碰到相同数据时,此时所有相同数据的排名都是一样的。


(3)Row_number函数返回一个唯一的值,当碰到相同数据时,排名按照记录集中记录的顺序依次递增。


例:
create table s_score
( s_id number(6)
 ,score number(4,2)
);
insert into s_score values(001,98);
insert into s_score values(002,66.5);
insert into s_score values(003,99);
insert into s_score values(004,98);
insert into s_score values(005,98);
insert into s_score values(006,80);

select
    s_id 
   ,score
   ,rank() over(order by score desc) rank
   ,dense_rank() over(order by score desc) dense_rank
   ,row_number() over(order by score desc) row_number
from s_score;

   S_ID  SCORE       RANK DENSE_RANK ROW_NUMBER
------- ------ ---------- ---------- ----------
      3  99.00          1          1          1
      1  98.00          2          2          2
      4  98.00          2          2          3
      5  98.00          2          2          4
      6  80.00          5          3          5
      2  66.50          6          4          6
        
排名/排序的时候,有时候,我们会想到利用伪列rownum,利用rownum确实可以解决某些场景下的问题(但是相对也比较复杂),而且有些
场景下的问题却很难解决。

例:取成绩前三名,并且前三名含有并列的情况    
通过上面例子,我们可以直观的看到,结果应该有5条记录。
select
    s_id 
   ,score
   ,dense_rank
from (
select
    s_id 
   ,score
   ,rank() over(order by score desc) rank
   ,dense_rank() over(order by score desc) dense_rank
   ,row_number() over(order by score desc) row_number
from s_score
) t
where dense_rank <= 3;

   S_ID  SCORE DENSE_RANK
------- ------ ----------
      3  99.00          1
      1  98.00          2
      5  98.00          2
      4  98.00          2
      6  80.00          3
      
如果只是简单的想到去用rownum <= 3 得到的结果显然不可能是正确的。

组内的排名或者排序是经常遇到的一种场景。
例如,取每个销售部门内,销售业绩最好的前三名。
      取每个班级内成绩排名信息等等..
      
取每个班级内每门课成绩排名第一的同学信息     
drop table S_SCORE;
create table S_SCORE
(
  S_ID  NUMBER(6),
  CLASS_ID VARCHAR2(2),
  COURSE VARCHAR2(20),
  SCORE NUMBER(5,2)
);

INSERT INTO S_SCORE VALUES(1001,'A','MATH','67');
INSERT INTO S_SCORE VALUES(1004,'B','MATH','88');
INSERT INTO S_SCORE VALUES(1002,'A','MATH','99');
INSERT INTO S_SCORE VALUES(1003,'A','MATH','55');
INSERT INTO S_SCORE VALUES(1001,'B','MATH','88');
INSERT INTO S_SCORE VALUES(1001,'B','MATH','70');
INSERT INTO S_SCORE VALUES(1001,'A','ORACLE','97');
INSERT INTO S_SCORE VALUES(1004,'B','ORACLE','48');
INSERT INTO S_SCORE VALUES(1002,'A','ORACLE','79');
INSERT INTO S_SCORE VALUES(1003,'A','ORACLE','65');
INSERT INTO S_SCORE VALUES(1001,'B','ORACLE','82');
INSERT INTO S_SCORE VALUES(1001,'B','ORACLE','78');

select
   s_id
  ,class_id
  ,course
  ,score
  ,dense_rank() over (partition by class_id,course order by score desc) drk
from S_SCORE
;

   S_ID CLASS_ID COURSE                 SCORE        DRK
------- -------- -------------------- ------- ----------
   1002 A        MATH                   99.00          1
   1001 A        MATH                   67.00          2
   1003 A        MATH                   55.00          3
   1001 A        ORACLE                 97.00          1
   1002 A        ORACLE                 79.00          2
   1003 A        ORACLE                 65.00          3
   1004 B        MATH                   88.00          1
   1001 B        MATH                   88.00          1
   1001 B        MATH                   70.00          2
   1001 B        ORACLE                 82.00          1
   1001 B        ORACLE                 78.00          2
   1004 B        ORACLE                 48.00          3
   
select
   s_id
  ,class_id
  ,course
  ,score
from (
select
   s_id
  ,class_id
  ,course
  ,score
  ,dense_rank() over (partition by class_id,course order by score desc) drk
from S_SCORE
) t
where drk = 1
;


   S_ID CLASS_ID COURSE                 SCORE
------- -------- -------------------- -------
   1002 A        MATH                   99.00
   1001 A        ORACLE                 97.00
   1004 B        MATH                   88.00
   1001 B        MATH                   88.00
   1001 B        ORACLE                 82.00   
   
rank()和dense_rank()用法相似,这里就不在举例说明了。可以将上面的例子中dense_rank()替换成rank()实现。


接下来,看一个使用row_number()的场景
例:查看每个部门最近一笔销售记录
select * from criss_sales order by dept_id,sale_date desc;

DEPT_ID SALE_DATE   GOODS_TYPE    SALE_CNT
------- ----------- ---------- -----------
D01     2014/5/4    G02                 80
D01     2014/4/30   G03                800
D01     2014/4/8    G01                200
D01     2014/3/4    G00                700
D02     2014/5/2    G03                900
D02     2014/4/27   G01                300
D02     2014/4/8    G02                100
D02     2014/3/6    G00                500

即,我们希望得到
D01     2014/5/4    G02                 80
D02     2014/5/2    G03                900
这两条记录

select
  dept_id
 ,sale_date
 ,goods_type
 ,sale_cnt
 ,row_number() over (partition by dept_id order by sale_date desc)
from criss_sales;

DEPT_ID SALE_DATE   GOODS_TYPE    SALE_CNT ROW_NUMBER()OVER(PARTITIONBYDE
------- ----------- ---------- ----------- ------------------------------
D01     2014/5/4    G02                 80                              1
D01     2014/4/30   G03                800                              2
D01     2014/4/8    G01                200                              3
D01     2014/3/4    G00                700                              4
D02     2014/5/2    G03                900                              1
D02     2014/4/27   G01                300                              2
D02     2014/4/8    G02                100                              3
D02     2014/3/6    G00                500                              4

select
  dept_id
 ,sale_date
 ,goods_type
 ,sale_cnt
from (
select
  dept_id
 ,sale_date
 ,goods_type
 ,sale_cnt
 ,row_number() over (partition by dept_id order by sale_date desc) rn
from criss_sales
) t
where rn = 1
;

DEPT_ID SALE_DATE   GOODS_TYPE    SALE_CNT
------- ----------- ---------- -----------
D01     2014/5/4    G02                 80
D02     2014/5/2    G03                900

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28929558/viewspace-1180283/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/28929558/viewspace-1180283/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值