Oracle分析函式使用總結

fengzj發表於2008-11-11

 Oracle分析函式使用總結
使用評級函式
評級函式(ranking function)用於計算等級、百分點、n分片等等,下面是幾個常用到的評級函式:
RANK():返回資料項在分組中的排名。特點:在排名相等的情況下會在名次中留下空位
DENSE_RANK():與RANK不同的是它在排名相等的情況下不會在名次中留下空位
CUME_DIST():返回特定值相對於一組值的位置:他是“cumulative distribution”(累積分佈)的簡寫
PERCENT_RANK():返回某個值相對於一組值的百分比排名
NTILE():返回n分片後的值,比如三分片、四分片等等
ROW_NUMBER():為每一條分組紀錄返回一個數字
下面我們分別舉例來說明這些函式的使用
1)RANK()與DENSE-RANK()
首先顯示下我們的源表資料的結構及部分資料:
SQL> desc all_sales;
 名稱                                      是否為空? 型別
 ----------------------------------------- -------- -----------
 YEAR                                      NOT NULL NUMBER(38)
 MONTH                                     NOT NULL NUMBER(38)
 PRD_TYPE_ID                               NOT NULL NUMBER(38)
 EMP_ID                                    NOT NULL NUMBER(38)
 AMOUNT                                             NUMBER(8,2)
SQL> select * from all_sales where rownum<11;

      YEAR      MONTH PRD_TYPE_ID     EMP_ID     AMOUNT
---------- ---------- ----------- ---------- ----------
      2003          1           1         21   10034.84
      2003          2           1         21   15144.65
      2003          3           1         21   20137.83
      2003          4           1         21   25057.45
      2003          5           1         21   17214.56
      2003          6           1         21   15564.64
      2003          7           1         21   12654.84
      2003          8           1         21   17434.82
      2003          9           1         21   19854.57
      2003         10           1         21   21754.19

已選擇10行。
好接下來我們將舉例來說明上述函式的使用:首先是RANK()與DENSE-RANK()的使用:
SQL> select
  2   prd_type_id,sum(amount),
  3   RANK() OVER (ORDER BY SUM(amount) DESC) AS rank,
  4   DENSE_RANK() OVER (ORDER BY SUM(amount) DESC) AS dense_rank
  5  from all_sales
  6  where year=2003
  7  group by prd_type_id
  8  order by rank;
PRD_TYPE_ID SUM(AMOUNT)       RANK DENSE_RANK
----------- ----------- ---------- ----------
          5                      1          1
          1   905081.84          2          2
          3   478270.91          3          3
          4   402751.16          4          4
          2   186381.22          5          5
注意:這裡PRD_TYPE_ID列為5的SUM(AMOUNT)的值為空,RANK()和DENSE-RANK在這一行的返回值為1。因為預設狀態下RANK()和DENSE-RANK()在遞減排序中將空值指定為最高排名1,而在遞增排序中則把它指定為最低排名。這裡還有一個問題就是我們的例子中沒有SUM(AMOUNT)相等的值,如果有的話RANK與DENSE-RANK將表現出區別比如上面的例子如果PRD_TYPE_ID為4的SUM(AMOUNT)的值也為:478270.91的話,那麼上面語句的輸出則為:
PRD_TYPE_ID SUM(AMOUNT)       RANK DENSE_RANK
----------- ----------- ---------- ----------
          5                      1          1
          1   905081.84          2          2
          3   478270.91          3          3
          4   478270.91          3          3
          2   186381.22          5          4
此外這裡還有兩個引數來限制空值的排序即:NULLS FIRST和NULLS LAST
我們還以上面的例子來看:
SQL> select
  2   prd_type_id,sum(amount),
  3   RANK() OVER (ORDER BY SUM(amount) DESC NULLS LAST) AS rank,
  4   DENSE_RANK() OVER (ORDER BY SUM(amount) DESC NULLS LAST) AS dense_rank
  5  from all_sales
  6  where year=2003
  7  group by prd_type_id
  8* order by rank

PRD_TYPE_ID SUM(AMOUNT)       RANK DENSE_RANK
----------- ----------- ---------- ----------
          1   905081.84          1          1
          3   478270.91          2          2
          4   402751.16          3          3
          2   186381.22          4          4
          5                      5          5
可以看出剛才我們不使用NULLS LAST時PRD_TYPE_ID為5的空值的排序位於第一,現在則位於第五。
接下來來看分析函式與PARTITION BY子句的結合使用:
當需要把分組劃分為子分組時,那麼我們便可以結合PRATITION BY子句和分析函式同時使用。如下例根據月份劃分銷量:
SQL> select
  2   prd_type_id,month,SUM(amount),
  3   RANK() OVER (PARTITION BY month ORDER BY SUM(amount) DESC) AS rank
  4  from all_sales
  5  where year=2003
  6  and amount IS NOT NULL
  7  GROUP BY prd_type_id,month
  8* ORDER BY month,rank
PRD_TYPE_ID      MONTH SUM(AMOUNT)       RANK
----------- ---------- ----------- ----------
          1          1    38909.04          1
          3          1    24909.04          2
          4          1    17398.43          3
          2          1    14309.04          4
          1          2     70567.9          1
          4          2     17267.9          2
          3          2     15467.9          3
          2          2     13367.9          4
          1          3    91826.98          1
          4          3    31026.98          2
          3          3    20626.98          3

PRD_TYPE_ID      MONTH SUM(AMOUNT)       RANK
----------- ---------- ----------- ----------
          2          3    16826.98          4
          1          4    120344.7          1
          3          4     23844.7          2
          4          4     16144.7          3
          2          4     15664.7          4
          1          5    97287.36          1
          4          5    20087.36          2
          3          5    18687.36          3
          2          5    18287.36          4
          1          6    57387.84          1
          4          6    33087.84          2

PRD_TYPE_ID      MONTH SUM(AMOUNT)       RANK
----------- ---------- ----------- ----------
          3          6    19887.84          3
          2          6    14587.84          4
          3          7    81589.04          1
          1          7    60929.04          2
          2          7    15689.04          3
          4          7    12089.04          4
          1          8    75608.92          1
          3          8    62408.92          2
          4          8    58408.92          3
          2          8    16308.92          4
          1          9    85027.42          1

PRD_TYPE_ID      MONTH SUM(AMOUNT)       RANK
----------- ---------- ----------- ----------
          4          9    49327.42          2
          3          9    46127.42          3
          2          9    19127.42          4
          1         10   105305.22          1
          4         10    75325.14          2
          3         10    70325.29          3
          2         10    13525.14          4
          1         11    55678.38          1
          3         11    46187.38          2
          4         11    42178.38          3
          2         11    16177.84          4

PRD_TYPE_ID      MONTH SUM(AMOUNT)       RANK
----------- ---------- ----------- ----------
          3         12    48209.04          1
          1         12    46209.04          2
          4         12    30409.05          3
          2         12    12509.04          4

已選擇48行。
接下來我們再來看分析函式與我們上次學的ROLLUP、CUBE、GROUPING SETS的結合使用:
SELECT
 prd_type_id,SUM(amount),
 RANK() OVER (ORDER BY SUM(amount) DESC NULLS LAST) AS rank
FROM all_sales
WHERE year=2003
GROUP BY ROLLUP(prd_type_id)
ORDER BY rank;

PRD_TYPE_ID        SUM(AMOUNT)        RANK
        1972485.13        1                    (注:RULLUP的總計排在了最前)
1        905081.84        2
3        478270.91        3
4        402751.16        4
2        186381.22        5
5                     6
SELECT
 prd_type_id,emp_id,SUM(amount),
 RANK() OVER (ORDER BY SUM(amount) DESC NULLS LAST) AS rank
FROM all_sales
WHERE year=2003
GROUP BY CUBE(prd_type_id,emp_id)
ORDER BY prd_type_id,emp_id;
PRD_TYPE_ID     EMP_ID SUM(AMOUNT)       RANK
----------- ---------- ----------- ----------
          1         21   197916.96         12
          1         22   214216.96         10
          1         23    98896.96         19
          1         24   207216.96         11
          1         25    93416.96         21
          1         26    93417.04         20
          1              905081.84          2
          2         21    20426.96         33
          2         22    19826.96         34
          2         23    19726.96         35
          2         24    43866.96         27

PRD_TYPE_ID     EMP_ID SUM(AMOUNT)       RANK
----------- ---------- ----------- ----------
          2         25    32266.96         31
          2         26    50266.42         24
          2              186381.22         14
          3         21   140326.96         15
          3         22   116826.96         16
          3         23   112026.96         17
          3         24    34829.96         29
          3         25    29129.96         32
          3         26    45130.11         26
          3              478270.91          3
          4         21   108326.96         18

PRD_TYPE_ID     EMP_ID SUM(AMOUNT)       RANK
----------- ---------- ----------- ----------
          4         22    81426.96         23
          4         23    92426.96         22
          4         24    47456.96         25
          4         25    33156.96         30
          4         26    39956.36         28
          4              402751.16          6
          5         21                     36
          5         22                     36
          5         23                     36
          5         24                     36
          5         25                     36

PRD_TYPE_ID     EMP_ID SUM(AMOUNT)       RANK
----------- ---------- ----------- ----------
          5         26                     36
          5                                36
                    21   466997.84          4
                    22   432297.84          5
                    23   323077.84          8
                    24   333370.84          7
                    25   187970.84         13
                    26   228769.93          9
                        1972485.13          1

已選擇42行。
SQL> SELECT
  2   prd_type_id,emp_id,SUM(amount),
  3   RANK() OVER (ORDER BY SUM(amount) DESC NULLS LAST) AS rank
  4  FROM all_sales
  5  WHERE year=2003
  6  GROUP BY GROUPING SETS(prd_type_id,emp_id)
  7  ORDER BY prd_type_id,emp_id;
PRD_TYPE_ID     EMP_ID SUM(AMOUNT)       RANK
----------- ---------- ----------- ----------
          1              905081.84          1
          2              186381.22         10
          3              478270.91          2
          4              402751.16          5
          5                                11
                    21   466997.84          3
                    22   432297.84          4
                    23   323077.84          7
                    24   333370.84          6
                    25   187970.84          9
                    26   228769.93          8

已選擇11行。
2)CUME-DIST()和PERCENT-RANK()函式
下面這個例子說明了CUME-DIST()與PERCENT-RANK()的使用,它得到的是銷量的累積分佈和百分比排名:
SQL> SELECT
  2   prd_type_id,SUM(amount),
  3   CUME_DIST() OVER (ORDER BY SUM(amount) DESC) AS cume_dist,
  4   PERCENT_RANK() OVER (ORDER BY SUM(amount) DESC) AS percent_rank
  5  FROM all_sales
  6  WHERE year=2003
  7  GROUP BY prd_type_id
  8  ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT)  CUME_DIST PERCENT_RANK
----------- ----------- ---------- ------------
          1   905081.84         .4          .25
          2   186381.22          1            1
          3   478270.91         .6           .5
          4   402751.16         .8          .75
          5                     .2            0
3)NTILE()函式的使用
前面我們已經介紹了這個函式的作用就是把記錄結果集分成N部分的意思,這個函式的引數為NTILE(buckets),這個bucket引數指定了分片的片數,下面我們看例子來說明
SQL> SELECT
  2   prd_type_id,SUM(amount),
  3   NTILE(2) OVER (ORDER BY SUM(amount) DESC) AS ntile
  4  FROM all_sales
  5  WHERE year=2003
  6  AND amount IS NOT NULL
  7  GROUP BY prd_type_id
  8  ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT)      NTILE
----------- ----------- ----------
          1   905081.84          1
          2   186381.22          2
          3   478270.91          1
          4   402751.16          2
注意這裡的N為2,因此分成了下面的1,2兩片
SQL> SELECT
  2   prd_type_id,SUM(amount),
  3   NTILE(3) OVER (ORDER BY SUM(amount) DESC) AS ntile
  4  FROM all_sales
  5  WHERE year=2003
  6  AND amount IS NOT NULL
  7  GROUP BY prd_type_id
  8  ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT)      NTILE
----------- ----------- ----------
          1   905081.84          1
          2   186381.22          3
          3   478270.91          1
          4   402751.16          2
注意這裡的N為3,因此分成了下面的1,2,3三片,這裡我的看法是當分片不均時,都是向上最加(即有兩個1片)
當N=4時就與RANK相同了
PRD_TYPE_ID SUM(AMOUNT)      NTILE
----------- ----------- ----------
          1   905081.84          1
          2   186381.22          4
          3   478270.91          2
          4   402751.16          3`
4)ROW-NUMBER()函式
SQL> SELECT
  2   prd_type_id,SUM(amount),
  3   ROW_NUMBER() OVER (ORDER BY SUM(amount) DESC) AS row_number
  4  FROM all_sales
  5  WHERE year=2003
  6  GROUP BY prd_type_id
  7  ORDER BY prd_type_id;
PRD_TYPE_ID SUM(AMOUNT) ROW_NUMBER
----------- ----------- ----------
          1   905081.84          2
          2   186381.22          5
          3   478270.91          3
          4   402751.16          4
          5                      1
這裡ROW-NUMBER()函式就相當於RANK()函式。
總結:在上面介紹的這些評級函式中其中RANK()、DENSE-RANK()、PERCENT-RANK()函式是比較常用的(相對於其他幾個而言),因此我們最好要掌握而其他幾個大家只要知道了解就可以了。
反百分點函式的使用
PERCENTILE-DISC(X)函式與CUME-DIST相反,它在每一個分組中檢查累積分佈的數值,直到找到大於或等於X的值。
PERCENTILE-CONT(X)函式與PERCENT-RANK()相反,在每一個分組中檢查百分比排名的值,直到
找到大於或等於X的值。
下面我們來看個例子獲取百分點大於等於0.6的銷售總量:
SQL> SELECT
  2   PERCENTILE_CONT(0.6) WITHIN GROUP (ORDER BY SUM(amount) DESC) AS percentile_cont,
  3   PERCENTILE_DISC(0.6) WITHIN GROUP (ORDER BY SUM(amount) DESC) AS percentile_disc
  4  FROM all_sales
  5  WHERE year=2003
  6  GROUP BY prd_type_id;
PERCENTILE_CONT PERCENTILE_DISC
--------------- ---------------
      417855.11       402751.16
視窗函式
視窗函式主要用來計算一定的記錄範圍內、一定的值域內、或一段時間內的累積和及移動平均值等。之所以叫“視窗”因為處理結果中使用了一個滑動的查詢結果集範圍。
1).計算累積和
下面這個例子是計算出2003年從1月到12月的累積銷量。
SQL> SELECT
  2   month 月份,SUM(amount) AS 月總銷量,
  3   SUM(SUM(amount)) OVER
  4    (ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 月累積銷量  --定義了視窗的起點和終點
  5  FROM all_sales
  6  WHERE year=2003
  7  GROUP BY month
  8  ORDER BY month;

      月份   月總銷量 月累積銷量
---------- ---------- ----------
         1   95525.55   95525.55
         2   116671.6  212197.15
         3  160307.92  372505.07
         4   175998.8  548503.87
         5  154349.44  702853.31
         6  124951.36  827804.67
         7  170296.16  998100.83
         8  212735.68 1210836.51
         9  199609.68 1410446.19
        10  264480.79 1674926.98
        11  160221.98 1835148.96

      月份   月總銷量 月累積銷量
---------- ---------- ----------
        12  137336.17 1972485.13

已選擇12行。       
那如果是計算6月到12月的累積銷量呢!!!
SQL> SELECT
  2   month 月份,SUM(amount) AS 月總銷量,
  3   SUM(SUM(amount)) OVER
  4    (ORDER BY month ROWS UNBOUNDED PRECEDING) AS 月累積銷量
  5  FROM all_sales
  6  WHERE year=2003
  7  AND month BETWEEN 6 AND 12       --6和12換為相應的月就可以了
  8  GROUP BY month
  9  ORDER BY month;

      月份   月總銷量 月累積銷量
---------- ---------- ----------
         6  124951.36  124951.36
         7  170296.16  295247.52
         8  212735.68   507983.2
         9  199609.68  707592.88
        10  264480.79  972073.67
        11  160221.98 1132295.65
        12  137336.17 1269631.82

已選擇7行。
2).計算移動平均值
計算本月與前三個月之間銷量的移動平均值
SQL> SELECT
  2   month 月份,SUM(amount) AS 月總銷量,
  3   AVG(SUM(amount)) OVER
  4    (ORDER BY month ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS 三月平均累積銷量
  5  FROM all_sales
  6  WHERE year=2003
  7  GROUP BY month
  8  ORDER BY month;

      月份   月總銷量 三月平均累積銷量
---------- ---------- ----------------
         1   95525.55         95525.55
         2   116671.6       106098.575      --前兩月的平均銷量
         3  160307.92       124168.357      --三月
         4   175998.8       137125.968      --本月加前三月
         5  154349.44        151831.94
         6  124951.36        153901.88
         7  170296.16        156398.94
         8  212735.68        165583.16
         9  199609.68        176898.22
        10  264480.79       211780.578
        11  160221.98       209262.033

      月份   月總銷量 三月平均累積銷量
---------- ---------- ----------------
        12  137336.17       190412.155

已選擇12行。
3).計算中心平均值
計算當前月份前、後各一個月內的銷量移動平均值:
SQL> SELECT
  2   month 月份,SUM(amount) AS 月總銷量,
  3   AVG(SUM(amount)) OVER
  4    (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS 平均累積銷量
  5  FROM all_sales
  6  WHERE year=2003
  7  GROUP BY month
  8  ORDER BY month;

      月份   月總銷量 平均累積銷量
---------- ---------- ------------
         1   95525.55   106098.575
         2   116671.6   124168.357
         3  160307.92   150992.773
         4   175998.8   163552.053
         5  154349.44   151766.533
         6  124951.36   149865.653
         7  170296.16   169327.733
         8  212735.68    194213.84
         9  199609.68   225608.717
        10  264480.79    208104.15
        11  160221.98   187346.313

      月份   月總銷量 平均累積銷量
---------- ---------- ------------
        12  137336.17   148779.075
4.FIRST-VALUE()和LAST-VALUE()函式的使用:
下面這個例子是用FIRST-VALUE()和LAST-VALUE()來獲得前一個月和後一個月的銷量:
SQL> SELECT
  2   month 月份,SUM(amount) AS 月總銷量,
  3   FIRST_VALUE(SUM(amount)) OVER
  4    (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS 前月銷量,
  5   LAST_VALUE(SUM(amount)) OVER
  6    (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS 後月銷量
  7  FROM all_sales
  8  WHERE year=2003
  9  GROUP BY month
 10  ORDER BY month;

      月份   月總銷量   前月銷量   後月銷量
---------- ---------- ---------- ----------
         1   95525.55   95525.55   116671.6
         2   116671.6   95525.55  160307.92
         3  160307.92   116671.6   175998.8
         4   175998.8  160307.92  154349.44
         5  154349.44   175998.8  124951.36
         6  124951.36  154349.44  170296.16
         7  170296.16  124951.36  212735.68
         8  212735.68  170296.16  199609.68
         9  199609.68  212735.68  264480.79
        10  264480.79  199609.68  160221.98
        11  160221.98  264480.79  137336.17

      月份   月總銷量   前月銷量   後月銷量
---------- ---------- ---------- ----------
        12  137336.17  160221.98  137336.17

已選擇12行。
還有一個例子是計算當前月與前、後各一個月的比率
SQL> SELECT
  2   month 月份,SUM(amount) AS 月總銷量,
  3   SUM(amount)/FIRST_VALUE(SUM(amount)) OVER
  4    (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS 當月與前月比率,
  5   SUM(amount)/LAST_VALUE(SUM(amount)) OVER
  6    (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS 當月與後月比率
  7  FROM all_sales
  8  WHERE year=2003
  9  GROUP BY month
 10  ORDER BY month;

      月份   月總銷量 當月與前月比率 當月與後月比率
---------- ---------- -------------- --------------
         1   95525.55              1     .818755807
         2   116671.6     1.22136538     .727796855
         3  160307.92     1.37400978     .910846665
         4   175998.8     1.09787963     1.14026199
         5  154349.44     .876991434     1.23527619
         6  124951.36     .809535558     .733729756
         7  170296.16     1.36289961     .800505867
         8  212735.68     1.24921008     1.06575833
         9  199609.68      .93829902     .754722791
        10  264480.79      1.3249898     1.65071478
        11  160221.98     .605798175     1.16664081

      月份   月總銷量 當月與前月比率 當月與後月比率
---------- ---------- -------------- --------------
        12  137336.17     .857161858              1

已選擇12行。

 

 

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/219982/viewspace-490822/,如需轉載,請註明出處,否則將追究法律責任。

相關文章