posts - 262,  comments - 221,  trackbacks - 0

          目錄
          ===============================================

          1.帶空值的排列
          2.Top/Bottom N查詢
          3.First/Last排名查詢
          4.按層次查詢

          一、帶空值的排列:

          在前面《Oracle開發(fā)專題之:分析函數(shù)2(Rank、Dense_rank、row_number)》一文中,我們已經(jīng)知道了如何為一批記錄進(jìn)行全排列、分組排列。假如被排列的數(shù)據(jù)中含有空值呢?

          SQL> select region_id, customer_id,
            
          2         sum(customer_sales) cust_sales,
            
          3         sum(sum(customer_sales)) over(partition by region_id) ran_total,
            
          4         rank() over(partition by region_id
            
          5                  order by sum(customer_sales) desc) rank
            
          6    from user_order
            
          7   group by region_id, customer_id;

           REGION_ID CUSTOMER_ID CUST_SALES  RAN_TOTAL       RANK
          ---------- ----------- ---------- ---------- ---------- 
                  10          31                    6238901          1
                  
          10          26    1808949    6238901          2
                  
          10          27    1322747    6238901          3
                  
          10          30    1216858    6238901          4
                  
          10          28     986964    6238901          5
                  
          10          29     903383    6238901          6

          我們看到這里有一條記錄的CUST_TOTAL字段值為NULL,但居然排在第一名了!顯然這不符合情理。所以我們重新調(diào)整完善一下我們的排名策略,看看下面的語句:

          SQL> select region_id, customer_id,
            
          2         sum(customer_sales) cust_total,
            
          3         sum(sum(customer_sales)) over(partition by region_id) reg_total,
            
          4         rank() over(partition by region_id 
                                  
          order by sum(customer_sales) desc NULLS LAST) rank
            
          5        from user_order
            
          6       group by region_id, customer_id;

           REGION_ID CUSTOMER_ID CUST_TOTAL  REG_TOTAL       RANK
          ---------- ----------- ---------- ---------- ----------
                  10          26    1808949     6238901           1
                  
          10          27    1322747    6238901           2
                  
          10          30    1216858    6238901           3
                  
          10          28     986964     6238901           4
                  
          10          29     903383     6238901           5
                  
          10          31     6238901                           6

          綠色高亮處,NULLS LAST/FIRST告訴Oracle讓空值排名最后后第一。

          注意是NULLS,不是NULL。

          二、Top/Bottom N查詢:

          在日常的工作生產(chǎn)中,我們經(jīng)常碰到這樣的查詢:找出排名前5位的訂單客戶、找出排名前10位的銷售人員等等。現(xiàn)在這個(gè)對(duì)我們來說已經(jīng)是很簡單的問題了。下面我們用一個(gè)實(shí)際的例子來演示:

          【1】找出所有訂單總額排名前3的大客戶:

          SQL> select *
          SQL
          >   from (select region_id,
          SQL
          >                customer_id,
          SQL
          >                sum(customer_sales) cust_total,
          SQL
          >                rank() over(order by sum(customer_sales) desc NULLS LAST) rank
          SQL>           from user_order
          SQL
          >          group by region_id, customer_id)
          SQL
          >  where rank <= 3;

           REGION_ID CUSTOMER_ID CUST_TOTAL       RANK
          ---------- ----------- ---------- ----------
                   9          25    2232703          1
                   
          8          17    1944281          2
                   
          7          14    1929774          3

          SQL
          > 

          【2】找出每個(gè)區(qū)域訂單總額排名前3的大客戶:
          SQL> select *
            
          2    from (select region_id,
            
          3                 customer_id,
            
          4                 sum(customer_sales) cust_total,
            
          5                 sum(sum(customer_sales)) over(partition by region_id) reg_total,
            
          6                 rank() over(partition by region_id
                                         
          order by sum(customer_sales) desc NULLS LAST) rank
            7            from user_order
            
          8           group by region_id, customer_id)
            
          9   where rank <= 3;

           REGION_ID CUSTOMER_ID CUST_TOTAL  REG_TOTAL       RANK
          ---------- ----------- ---------- ---------- ----------
                   5           4    1878275    5585641          1
                   
          5           2    1224992    5585641          2
                   
          5           5    1169926    5585641          3
                   
          6           6    1788836    6307766          1
                   
          6           9    1208959    6307766          2
                   
          6          10    1196748    6307766          3
                   
          7          14    1929774    6868495          1
                   
          7          13    1310434    6868495          2
                   
          7          15    1255591    6868495          3
                   
          8          17    1944281    6854731          1
                   
          8          20    1413722    6854731          2
                   
          8          18    1253840    6854731          3
                   
          9          25    2232703    6739374          1
                   
          9          23    1224992    6739374          2
                   
          9          24    1224992    6739374          2
                  
          10          26    1808949    6238901          1
                  
          10          27    1322747    6238901          2
                  
          10          30    1216858    6238901          3

          18 rows selected.

          三、First/Last排名查詢:

          想象一下下面的情形:找出訂單總額最多、最少的客戶。按照前面我們學(xué)到的知識(shí),這個(gè)至少需要2個(gè)查詢。第一個(gè)查詢按照訂單總額降序排列以期拿到第一名,第二個(gè)查詢按照訂單總額升序排列以期拿到最后一名。是不是很煩?因?yàn)镽ank函數(shù)只告訴我們排名的結(jié)果,卻無法自動(dòng)替我們從中篩選結(jié)果。

          幸好Oracle為我們?cè)谂帕泻瘮?shù)之外提供了兩個(gè)額外的函數(shù):first、last函數(shù),專門用來解決這種問題。還是用實(shí)例說話:
          SQL> select min(customer_id)
            2         keep (dense_rank first order by sum(customer_sales) desc) first,
            
          3         min(customer_id)
            
          4         keep (dense_rank last order by sum(customer_sales) desclast
            
          5    from user_order
            
          6   group by customer_id;

               FIRST       LAST
          ---------- ----------
                  31          1

          這里有幾個(gè)看起來比較疑惑的地方:

          ①為什么這里要用min函數(shù)
          ②Keep這個(gè)東西是干什么的
          ③fist/last是干什么的
          ④dense_rank和dense_rank()有什么不同,能換成rank嗎?

          首先解答一下第一個(gè)問題:min函數(shù)的作用是用于當(dāng)存在多個(gè)First/Last情況下保證返回唯一的記錄。假如我們?nèi)サ魰?huì)有什么樣的后果呢?
          SQL> select keep (dense_rank first order by sum(customer_sales) desc) first, 
            
          2             keep (dense_rank last order by sum(customer_sales) desc) last
            
          3    from user_order
            
          4   group by customer_id;
          select keep (dense_rank first order by sum(customer_sales) desc) first,
                                  
          *
          ERROR at line 
          1:
          ORA
          -00907: missing right parenthesis

          接下來看看第2個(gè)問題:keep是干什么用的?從上面的結(jié)果我們已經(jīng)知道Oracle對(duì)排名的結(jié)果只“保留”2條數(shù)據(jù),這就是keep的作用。告訴Oracle只保留符合keep條件的記錄。

          那么什么才是符合條件的記錄呢?這就是第3個(gè)問題了。dense_rank是告訴Oracle排列的策略,first/last則告訴最終篩選的條件。

          第4個(gè)問題:如果我們把dense_rank換成rank呢?
          SQL> select min(region_id)
            
          2          keep(rank first order by sum(customer_sales) desc) first,
            
          3         min(region_id)
            
          4          keep(rank last order by sum(customer_sales) desc) last
            
          5    from user_order
            
          6   group by region_id;
          select min(region_id)
          *
          ERROR at line 
          1:
          ORA
          -02000: missing DENSE_RANK

          四、按層次查詢:

          現(xiàn)在我們已經(jīng)見識(shí)了如何通過Oracle的分析函數(shù)來獲取Top/Bottom N,第一個(gè),最后一個(gè)記錄。有時(shí)我們會(huì)收到類似下面這樣的需求:找出訂單總額排名前1/5的客戶。

          很熟悉是不?我們馬上會(huì)想到第二點(diǎn)中提到的方法,可是rank函數(shù)只為我們做好了排名,并不知道每個(gè)排名在總排名中的相對(duì)位置,這時(shí)候就引入了另外一個(gè)分析函數(shù)NTile,下面我們就以上面的需求為例來講解一下:

          SQL> select region_id,
            
          2         customer_id,
            
          3         ntile(5over(order by sum(customer_sales) desc) til
            
          4    from user_order
            
          5   group by region_id, customer_id;

           REGION_ID CUSTOMER_ID       TILE
          ---------- ----------- ----------
                  10          31          1
                   
          9          25           1
                  
          10          26          1
                   
          6           6            1         
                   
          8          18           2
                   
          5           2            2
                   
          9          23           3
                   
          6           9            3
                   
          7          11           3
                   
          5           3            4
                   
          6           8            4
                   
          8          16           4
                   
          6           7            5
                  
          10          29          5
                   
          5           1            5

          Ntil函數(shù)為各個(gè)記錄在記錄集中的排名計(jì)算比例,我們看到所有的記錄被分成5個(gè)等級(jí),那么假如我們只需要前1/5的記錄則只需要截取TILE的值為1的記錄就可以了。假如我們需要排名前25%的記錄(也就是1/4)那么我們只需要設(shè)置ntile(4)就可以了。

          參考資料:《Mastering Oracle SQL》(By Alan Beaulieu, Sanjay Mishra O'Reilly June 2004  0-596-00632-2)  


          -------------------------------------------------------------
          生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。
          posted on 2008-06-27 09:44 Paul Lin 閱讀(6607) 評(píng)論(1)  編輯  收藏 所屬分類: Oracle 開發(fā)


          FeedBack:
          # re: 【原】Oracle應(yīng)用專題之:分析函數(shù)3(Top/Bottom N、First/Last、NTile)[未登錄]
          2008-09-10 11:56 | ty
          講的真是很清楚,非常不錯(cuò)~!  回復(fù)  更多評(píng)論
            
          <2008年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          常用鏈接

          留言簿(21)

          隨筆分類

          隨筆檔案

          BlogJava熱點(diǎn)博客

          好友博客

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 鄂托克旗| 新化县| 上栗县| 绥化市| 酒泉市| 准格尔旗| 贵港市| 德惠市| 醴陵市| 陇川县| 固原市| 石景山区| 平阴县| 平湖市| 河源市| 类乌齐县| 通州区| 通道| 错那县| 凤冈县| 龙口市| 安达市| 湾仔区| 永兴县| 临朐县| 城步| 和平县| 南皮县| 全州县| 安义县| 班玛县| 灵宝市| 达尔| 陆河县| 尖扎县| 左权县| 青阳县| 斗六市| 屯门区| 西城区| 昌平区|