分析函數1之語法

===============================================
1.Oracle分析函數簡介
2. Oracle分析函數簡單實例
3.分析函數OVER解析

一、Oracle分析函數簡介:

在日常的生產環境中,我們接觸得比較多的是OLTP系統(即Online Transaction Process),這些系統的特點是具備實時要求,或者至少說對響應的時間多長有一定的要求;其次這些系統的業務邏輯一般比較複雜,可能需要經過多次的運算。比如我們經常接觸到的電子商城。

在這些系統之外,還有一種稱之爲OLAP的系統(即Online Aanalyse Process),這些系統一般用於系統決策使用。通常和數據倉庫、數據分析、數據挖掘等概念聯繫在一起。這些系統的特點是數據量大,對實時響應的要求不高或者根本不關注這方面的要求,以查詢、統計操作爲主。

我們來看看下面的幾個典型例子:
①查找上一年度各個銷售區域排名前10的員工
②按區域查找上一年度訂單總額佔區域訂單總額20%以上的客戶
③查找上一年度銷售最差的部門所在的區域
④查找上一年度銷售最好和最差的產品

我們看看上面的幾個例子就可以感覺到這幾個查詢和我們日常遇到的查詢有些不同,具體有:

①需要對同樣的數據進行不同級別的聚合操作
②需要在表內將多條數據和同一條數據進行多次的比較
③需要在排序完的結果集上進行額外的過濾操作
分析函數語法:
FUNCTION_NAME(<argument>,<argument>...)
OVER
(<Partition-Clause>
<Order-by-Clause>
<Windowing Clause>)----窗口clause

RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.   默認窗口值
 RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING.    窗口值
例:
sum(sal) over (partition by deptno order by ename) new_alias
sum就是函數名
(sal)是分析函數的參數,每個函數有0~3個參數,參數可以是表達式,例如:sum(sal+comm)
over 是一個關鍵字,用於標識分析函數,否則查詢分析器不能區別sum()聚集函數和sum()分析函數
partition by deptno 是可選的分區子句,如果不存在任何分區子句,則全部的結果集可看作一個單一的大區
order by ename 是可選的order by 子句,有些函數需要它,有些則不需要.依靠已排序數據的那些函數,如:用於訪問結果集中前一行和後一行的LAG和LEAD,必須使用,其它函數,如AVG,則不需要.在使用了任何排序的開窗函數時,該子句是強制性的,它指定了在計算分析函數時一組內的數據是如何排序的.
1)FUNCTION子句
ORACLE提供了26個分析函數,按功能分5類
分析函數分類
等級(ranking)函數:用於尋找前N種查詢
開窗(windowing)函數:用於計算不同的累計,如SUM,COUNT,AVG,MIN,MAX等,作用於數據的一個窗口上
例:
sum(t.sal) over (order by t.deptno,t.ename) running_total,
sum(t.sal) over (partition by t.deptno order by t.ename) department_total
製表(reporting)函數:與開窗函數同名,作用於一個分區或一組上的所有列
例:
sum(t.sal) over () running_total2,
sum(t.sal) over (partition by t.deptno ) department_total2
製表函數與開窗函數的關鍵不同之處在於OVER語句上缺少一個ORDER BY子句!
LAG,LEAD函數:這類函數允許在結果集中向前或向後檢索值,爲了避免數據的自連接,它們是非常用用的.
VAR_POP,VAR_SAMP,STDEV_POPE及線性的衰減函數:計算任何未排序分區的統計值
2)PARTITION子句
按照表達式分區(就是分組),如果省略了分區子句,則全部的結果集被看作是一個單一的組
3)ORDER BY子句
分析函數中ORDER BY的存在將添加一個默認的開窗子句,這意味着計算中所使用的行的集合是當前分區中當前行和前面所有行,沒有ORDER BY時,默認的窗口是全部的分區 在Order by 子句後可以添加nulls last,如:order by comm desc nulls last   表示排序時忽略comm列爲空的行.   
4)WINDOWING子句
用於定義分析函數將在其上操作的行的集合
Windowing子句給出了一個定義變化或固定的數據窗口的方法,分析函數將對這些數據進行操作
默認的窗口是一個固定的窗口,僅僅在一組的第一行開始,一直繼續到當前行,要使用窗口,必須使用ORDER BY子句
根據2個標準可以建立窗口:數據值的範圍(RANGES)或與當前行的行偏移量.
5)Rang窗口
Range 5 preceding:將產生一個滑動窗口,他在組中擁有當前行以前5行的集合
ANGE窗口僅對NUMBERS和DATES起作用,因爲不可能從VARCHAR2中增加或減去N個單元
另外的限制是ORDER BY中只能有一列,因而範圍實際上是一維的,不能在N維空間中
例:
avg(t.sal) over(order by t.hiredate asc range 100 preceding) 統計前100天平均工資
6)Row窗口
利用ROW分區,就沒有RANGE分區那樣的限制了,數據可以是任何類型,且ORDER BY 可以包括很多列
7)Specifying窗口
UNBOUNDED PRECEDING:這個窗口從當前分區的每一行開始,並結束於正在處理的當前行
CURRENT ROW:該窗口從當前行開始(並結束)
Numeric Expression PRECEDING:對該窗口從當前行之前的數字表達式(Numeric Expression)的行開始,對RANGE來說,從從行序值小於數字表達式的當前行的值開始.
Numeric Expression FOLLOWING:該窗口在當前行Numeric Expression行之後的行終止(或開始),且從行序值大於當前行Numeric Expression行的範圍開始(或終止)
range between 100 preceding and 100 following:當前行100前,當前後100後
注意:分析函數允許你對一個數據集進排序和篩選,這是SQL從來不能實現的.除了最後的Order by子句之外,分析函數是在查詢中執行的最後的操作集,這樣的話,就不能直接在謂詞中使用分析函數,即不能在上面使用where或having子句!!!
 
二、Oracle分析函數簡單實例:

下面我們通過一個實際的例子:按區域查找上一年度訂單總額佔區域訂單總額20%以上的客戶,來看看分析函數的應用。

【1】測試環境:
 SQL> desc orders_tmp;
  Name                           Null?    Type
  ----------------------- -------- ----------------
  CUST_NBR                    NOT NULL NUMBER(5)
  REGION_ID                   NOT NULL NUMBER(5)
  SALESPERSON_ID      NOT NULL NUMBER(5)
  YEAR                              NOT NULL NUMBER(4)
  MONTH                         NOT NULL NUMBER(2)
  TOT_ORDERS              NOT NULL NUMBER(7)
  TOT_SALES                 NOT NULL NUMBER(11,2)

【2】測試數據:
 SQL> select * from orders_tmp;
 
   CUST_NBR       REGION_ID    SALESPERSON_ID               YEAR        MONTH  TOT_ORDERS  TOT_SALES
 ---------- ---------- -------------- ---------- ---------- ---------- ----------
         11          7             11                       2001          7          2      12204
          4          5              4                       2001          10         2      37802
          7          6              7                       2001          2          3       3750
         10          6              8                       2001          1          2      21691
         10          6              7                       2001          2          3      42624
         15          7             12                       2000          5          6         24
         12          7              9                       2000          6          2      50658
          1          5              2                       2000          3          2      44494
          1          5              1                       2000          9          2      74864
          2          5              4                       2000          3          2      35060
          2          5              4                       2000          4          4       6454
          2          5              1                       2000         10          4      35580
          4          5              4                       2000         12          2      39190
 
 13 rows selected.

【3】測試語句:
 SQL> select o.cust_nbr customer,
   2         o.region_id region,
   3         sum(o.tot_sales) cust_sales,
   4         sum(sum(o.tot_sales)) over(partition by o.region_id) region_sales
   5    from orders_tmp o
   6   where o.year = 2001
   7   group by o.region_id, o.cust_nbr;
 
   CUSTOMER        REGION     CUST_SALES  REGION_SALES
 ----------     ----------  ----------  ------------
          4             5      37802        37802
          7             6       3750        68065
         10             6      64315        68065
         11             7      12204        12204
 

三、分析函數OVER解析:

請注意上面的綠色高亮部分,group by的意圖很明顯:將數據按區域ID,客戶進行分組,那麼Over這一部分有什麼用呢?假如我們只需要統計每個區域每個客戶的訂單總額,那麼我們只需要group by o.region_id,o.cust_nbr就夠了。但我們還想在每一行顯示該客戶所在區域的訂單總額,這一點和前面的不同:需要在前面分組的基礎上按區域累加。很顯然group by和sum是無法做到這一點的(因爲聚集操作的級別不一樣,前者是對一個客戶,後者是對一批客戶)。

這就是over函數的作用了!它的作用是告訴SQL引擎:按區域對數據進行分區,然後累積每個區域每個客戶的訂單總額(sum(sum(o.tot_sales)))。

現在我們已經知道2001年度每個客戶及其對應區域的訂單總額,那麼下面就是篩選那些個人訂單總額佔到區域訂單總額20%以上的大客戶了
 SQL> select *
   2    from (select o.cust_nbr customer,
   3                 o.region_id region,
   4                 sum(o.tot_sales) cust_sales,
   5                 sum(sum(o.tot_sales)) over(partition by o.region_id) region_sales
   6            from orders_tmp o
   7           where o.year = 2001
   8           group by o.region_id, o.cust_nbr) all_sales
   9   where all_sales.cust_sales > all_sales.region_sales * 0.2;
 
   CUSTOMER     REGION CUST_SALES REGION_SALES
 ---------- ---------- ---------- ------------
          4          5      37802        37802
         10          6      64315        68065
         11          7      12204        12204
 
 SQL>

現在我們已經知道這些大客戶是誰了!哦,不過這還不夠,如果我們想要知道每個大客戶所佔的訂單比例呢?看看下面的SQL語句,只需要一個簡單的Round函數就搞定了。
 SQL> select all_sales.*,
   2         100 * round(cust_sales / region_sales, 2) || '%' Percent
   3    from (select o.cust_nbr customer,
   4                 o.region_id region,
   5                 sum(o.tot_sales) cust_sales,
   6                 sum(sum(o.tot_sales)) over(partition by o.region_id) region_sales
   7            from orders_tmp o
   8           where o.year = 2001
   9           group by o.region_id, o.cust_nbr) all_sales
  10   where all_sales.cust_sales > all_sales.region_sales * 0.2;
 
   CUSTOMER     REGION    CUST_SALES REGION_SALES PERCENT
 ----------     ---------- ---------- ------------ ----------------------------------------
          4           5     37802        37802    100%
         10           6     64315        68065      94%
         11           7     12204        12204    100%
 
 SQL>

總結:

①Over函數指明在那些字段上做分析,其內跟Partition by表示對數據進行分組。注意Partition by可以有多個字段。

②Over函數可以和其它聚集函數、分析函數搭配,起到不同的作用。例如這裏的SUM,還有諸如Rank,Dense_rank等。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章