<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 262,  comments - 221,  trackbacks - 0

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

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

    一、帶空值的排列:

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

    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,但居然排在第一名了!顯然這不符合情理。所以我們重新調整完善一下我們的排名策略,看看下面的語句:

    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查詢:

    在日常的工作生產中,我們經常碰到這樣的查詢:找出排名前5位的訂單客戶、找出排名前10位的銷售人員等等。現在這個對我們來說已經是很簡單的問題了。下面我們用一個實際的例子來演示:

    【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】找出每個區域訂單總額排名前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排名查詢:

    想象一下下面的情形:找出訂單總額最多、最少的客戶。按照前面我們學到的知識,這個至少需要2個查詢。第一個查詢按照訂單總額降序排列以期拿到第一名,第二個查詢按照訂單總額升序排列以期拿到最后一名。是不是很煩?因為Rank函數只告訴我們排名的結果,卻無法自動替我們從中篩選結果。

    幸好Oracle為我們在排列函數之外提供了兩個額外的函數:first、last函數,專門用來解決這種問題。還是用實例說話:
    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

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

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

    首先解答一下第一個問題:min函數的作用是用于當存在多個First/Last情況下保證返回唯一的記錄。假如我們去掉會有什么樣的后果呢?
    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個問題:keep是干什么用的?從上面的結果我們已經知道Oracle對排名的結果只“保留”2條數據,這就是keep的作用。告訴Oracle只保留符合keep條件的記錄。

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

    第4個問題:如果我們把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

    四、按層次查詢:

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

    很熟悉是不?我們馬上會想到第二點中提到的方法,可是rank函數只為我們做好了排名,并不知道每個排名在總排名中的相對位置,這時候就引入了另外一個分析函數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函數為各個記錄在記錄集中的排名計算比例,我們看到所有的記錄被分成5個等級,那么假如我們只需要前1/5的記錄則只需要截取TILE的值為1的記錄就可以了。假如我們需要排名前25%的記錄(也就是1/4)那么我們只需要設置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 閱讀(6604) 評論(1)  編輯  收藏 所屬分類: Oracle 開發


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

    常用鏈接

    留言簿(21)

    隨筆分類

    隨筆檔案

    BlogJava熱點博客

    好友博客

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产在线精品观看免费观看| 亚洲1区2区3区精华液| 无码国产精品一区二区免费vr | 亚洲欧洲校园自拍都市| 免费阿v网站在线观看g| 色欲aⅴ亚洲情无码AV蜜桃| 久久精品亚洲福利| 久久精品成人免费观看| 亚洲精品一卡2卡3卡四卡乱码| 亚洲一区精品伊人久久伊人| 黄色网址免费大全| 三级片免费观看久久| 亚洲视频在线免费看| 免费一级毛片在播放视频| 国产精品免费AV片在线观看| 亚洲av片在线观看| 久久精品国产亚洲AV电影| 日本免费人成黄页在线观看视频 | 国产精品国产亚洲精品看不卡| 91情侣在线精品国产免费| 国产成人自产拍免费视频| 亚洲一区二区三区在线网站| 中文字幕精品无码亚洲字| 日韩高清在线免费看| a在线观看免费视频| 亚洲AV无码国产精品永久一区| 亚洲成熟xxxxx电影| 免费大片黄手机在线观看| 日日麻批免费40分钟日本的| 人碰人碰人成人免费视频| 亚洲毛片基地4455ww| 亚洲AV午夜成人片| 亚洲毛片av日韩av无码| 四虎成人精品一区二区免费网站| 久久免费国产视频| ssswww日本免费网站片| 免费亚洲视频在线观看| 亚洲中文字幕无码中文| 亚洲二区在线视频| 在线观看免费无码视频| 国产精品亚洲片在线花蝴蝶|