[转]oracle分析函数Rank, Dense_rank, row_number
oracle分析函數Rank, Dense_rank, row_number
分析函數2(Rank, Dense_rank, row_number)
?
目錄
===============================================
1.使用rownum為記錄排名
2.使用分析函數來為記錄排名
3.使用分析函數為記錄進行分組排名
一、使用rownum為記錄排名:
在前面一篇《Oracle開發專題之:分析函數》,我們認識了分析函數的基本應用,現在我們再來考慮下面幾個問題:
①對所有客戶按訂單總額進行排名
②按區域和客戶訂單總額進行排名
③找出訂單總額排名前13位的客戶
④找出訂單總額最高、最低的客戶
⑤找出訂單總額排名前25%的客戶
按照前面第一篇文章的思路,我們只能做到對各個分組的數據進行統計,如果需要排名的話那么只需要簡單地加上rownum不就行了嗎?事實情況是否如此想象般簡單,我們來實踐一下。
【1】測試環境:
SQL>?desc?user_order;
?Name??????????????????????????????????????Null?????Type
?-----------------------------------------?--------?----------------------------
?REGION_ID??????????????????????????????????????????NUMBER(2)
?CUSTOMER_ID??????????????????????????????????NUMBER(2)
?CUSTOMER_SALES??????????????????????????NUMBER
【2】測試數據:
SQL>?select?*?from?user_order?order?by?customer_sales;
?REGION_ID?CUSTOMER_ID?CUSTOMER_SALES
----------?-----------?--------------
?????????5???????????1????????????? 151162
????????10??????????29????????? ?? 903383
?????????6???????????7????????????? 971585
????????10??????????28??????????? 986964
?????????9??????????21???????????1020541
?????????9??????????22?????????? 1036146
?????????8??????????16?????????? 1068467
?????????6???????????8??????????? 1141638
?????????5???????????3??????????? 1161286
?????????5???????????5??????????? 1169926
?????????8??????????19?????????? 1174421
?????????7??????????12?????????? 1182275
?????????7??????????11?????????? 1190421
?????????6??????????10?????????? 1196748
?????????6???????????9??????????? 1208959
????????10??????????30??????????1216858
?????????5???????????? 2??????????????? 1224992
???????????9???????????? 24????????????? 1224992
???????????9???????????? 23????????????? 1224992
?????????? 8??????????18?????????? 1253840
?????????7??????????15?????????? 1255591
?????????7??????????13?????????? 1310434
????????10??????????27????????? 1322747
?????????8??????????20?????????? 1413722
?????????6???????????6??????????? 1788836
????????10??????????26????????? 1808949
?????????5???????????4??????????? 1878275
?????????7??????????14?????????? 1929774
?????????8??????????17?????????? 1944281
?????????9??????????25?????????? 2232703
30?rows?selected.
注意這里有3條記錄的訂單總額是一樣的。假如我們現在需要篩選排名前12位的客戶,如果使用rownum會有什么樣的后果呢?
SQL>?select?rownum,?t.*
??2????from?(select?*?
??3????????????from?user_order
??4???????????order?by?customer_sales?desc)?t
??5???where?rownum?<=?12
??6???order?by?customer_sales?desc;
????ROWNUM??REGION_ID?CUSTOMER_ID?CUSTOMER_SALES
----------?----------?-----------?--------------
?????????1??????????9???????????????? 25????????2232703
?????????2??????????8???????????????? 17????????1944281
?????????3??????????7?????????????????14????????1929774
?????????4??????????5???????????????????4????????1878275
?????????5?????????10????????????????26????????1808949
?????????6??????????6?????????????????? 6????????1788836
?????????7??????????8???????????????? 20????????1413722
?????????8?????????10??????????????? 27????????1322747
?????????9??????????7??????????????? 13????????1310434
????????10??????????7?????????????? 15????????1255591
????????11??????????8?????????????? 18????????1253840
????????? 12???????????? 5???????????????????? 2????????? 1224992
12?rows?selected.
很明顯假如只是簡單地按rownum進行排序的話,我們漏掉了另外兩條記錄(參考上面的結果)。
二、使用分析函數來為記錄排名:
針對上面的情況,Oracle從8i開始就提供了3個分析函數:rand,dense_rank,row_number來解決諸如此類的問題,下面我們來看看這3個分析函數的作用以及彼此之間的區別:
Rank,Dense_rank,Row_number函數為每條記錄產生一個從1開始至N的自然數,N的值可能小于等于記錄的總數。這3個函數的唯一區別在于當碰到相同數據時的排名策略。
①ROW_NUMBER:
Row_number函數返回一個唯一的值,當碰到相同數據時,排名按照記錄集中記錄的順序依次遞增。?
②DENSE_RANK:
Dense_rank函數返回一個唯一的值,除非當碰到相同數據時,此時所有相同數據的排名都是一樣的。?
③RANK:
Rank函數返回一個唯一的值,除非遇到相同的數據時,此時所有相同數據的排名是一樣的,同時會在最后一條相同記錄和下一條不同記錄的排名之間空出排名。
這樣的介紹有點難懂,我們還是通過實例來說明吧,下面的例子演示了3個不同函數在遇到相同數據時不同排名策略:
SQL>?select?region_id,?customer_id,?sum(customer_sales)?total,
??2?????????rank()?over(order?by?sum(customer_sales)?desc)?rank,
??3?????????dense_rank()?over(order?by?sum(customer_sales)?desc)?dense_rank,
??4?????????row_number()?over(order?by?sum(customer_sales)?desc)?row_number
??5????from?user_order
??6???group?by?region_id,?customer_id;
?REGION_ID?CUSTOMER_ID??????TOTAL???????RANK?DENSE_RANK?ROW_NUMBER
----------?-----------?----------?----------?----------?----------
? ? ????????
?????????8??????????18????????????????1253840?????????11?????????11?????????11
?????????5???????????2?????????????????1224992?????????12?????????12?????????12
?????????9??????????23????????????????1224992?????????12?????????12?????????13
?????????9??????????24????????????????1224992?????????12?????????12?????????14
????????10??????????30???????????????1216858?????????15?????????? 13??????????? 15
? ?
30?rows?selected.
請注意上面的綠色高亮部分,這里生動的演示了3種不同的排名策略:
①對于第一條相同的記錄,3種函數的排名都是一樣的:12
②當出現第二條相同的記錄時,Rank和Dense_rank依然給出同樣的排名12;而row_number則順延遞增為13,依次類推至第三條相同的記錄
③當排名進行到下一條不同的記錄時,可以看到Rank函數在12和15之間空出了13,14的排名,因為這2個排名實際上已經被第二、三條相同的記錄占了。而Dense_rank則順序遞增。row_number函數也是順序遞增
比較上面3種不同的策略,我們在選擇的時候就要根據客戶的需求來定奪了:
①假如客戶就只需要指定數目的記錄,那么采用row_number是最簡單的,但有漏掉的記錄的危險
②假如客戶需要所有達到排名水平的記錄,那么采用rank或dense_rank是不錯的選擇。至于選擇哪一種則看客戶的需要,選擇dense_rank或得到最大的記錄
三、使用分析函數為記錄進行分組排名:
上面的排名是按訂單總額來進行排列的,現在跟進一步:假如是為各個地區的訂單總額進行排名呢?這意味著又多了一次分組操作:對記錄按地區分組然后進行排名。幸虧Oracle也提供了這樣的支持,我們所要做的僅僅是在over函數中order by的前面增加一個分組子句:partition by region_id。
SQL>?select?region_id,?customer_id,?
???????????????sum(customer_sales)?total,
??2?????????rank()?over(partition?by?region_id
????????????????????????order?by?sum(customer_sales)?desc)?rank,
??3?????????dense_rank()?over(partition?by?region_id
????????????????????????order?by?sum(customer_sales)?desc)?dense_rank,
??4?????????row_number()?over(partition?by?region_id
????????????????????????order?by?sum(customer_sales)?desc)?row_number
??5????from?user_order
??6???group?by?region_id,?customer_id;
?REGION_ID?CUSTOMER_ID??????TOTAL???????RANK?DENSE_RANK?ROW_NUMBER
----------?-----------?----------?----------?----------?----------
?????????5???????????4????????????????1878275??????????1??????????1??????????1
?????????5???????????2??????????????? 1224992??????????2??????????2??????????2
?????????5???????????5??????????????? 1169926??????????3??????????3??????????3
?????????6???????????6??????????????? 1788836??????????1??????????1??????????1
?????????6???????????9??????????????? 1208959??????????2??????????2??????????2
?????????6??????????10????????????? ?1196748??????????3??????????3??????????3???????
?
30?rows?selected.
現在我們看到的排名將是基于各個地區的,而非所有區域的了!Partition by 子句在排列函數中的作用是將一個結果集劃分成幾個部分,這樣排列函數就能夠應用于這各個子集。
前面我們提到的5個問題已經解決了2個了(第1,2),剩下的3個問題(Top/Bottom N,First/Last, NTile)會在下一篇講解。
?原文地址:http://www.cnblogs.com/wuyisky/archive/2010/02/24/oracle_rank.html
轉載于:https://www.cnblogs.com/autumnlj/p/5815297.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的[转]oracle分析函数Rank, Dense_rank, row_number的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 剑指Offer_52_正则表达式匹配
- 下一篇: UUID,加密解密算法的使用