1. 程式人生 > >oracle 之分析函式 over (partition by ...order by ...)

oracle 之分析函式 over (partition by ...order by ...)

一:分析函式over
Oracle從8.1.6開始提供分析函式,分析函式用於計算基於組的某種聚合值,它和聚合函式的不同之處是對於每個組返回多行,而聚合函式對於每個組只返回一行。

1、分析函式和聚合函式的不同之處:

分析函式和聚合函式很多是同名的,意思也一樣,只是聚合函式用group by分組,每個分組返回一個統計值,而分析函式採用partition by分組,並且每組每行都可以返回一個統計值。簡單的說就是聚合函式返回統計結果,分析函式返回明細加統計結果。

(一)、分析函式語法:
  FUNCTION_NAME(<argument>,<argument>...)
  OVER


  (<Partition-Clause><Order-by-Clause><Windowing Clause>)

例:(在oracle示例庫中演示,使用者scott)
select ename,sum(sal) over (partition by deptno order by ename) new_alias from emp;
a、sum就是函式名(FUNCTION_NAME)
b、(sal)是分析函式的引數,每個函式有0~3個引數,引數可以是表示式,例如:sum(sal+comm)
c、over 是一個關鍵字,用於標識分析函式,否則查詢分析器不能區別sum()聚集函式和sum()分析函式
d、partition by deptno (按相應的值(deptno)進行分組統計)是可選的分割槽子句,如果不存在任何分割槽子句,則全部的結果集可看作一個單一的大區
e、order by ename 是可選的order by 子句,有些函式需要它,有些則不需要.依靠已排序資料的那些函式。

即:分析函式帶有一個開窗函式over(),包含三個分析子句:

分組(partition by)
排序(order by)
視窗(rows)

示例1:

SELECT empno,ename,job,deptno,  ----查詢基礎欄位
	COUNT(*) over(PARTITION BY deptno) cnt_dept_man,   --- 查詢部門人員數量	(等同於用部門deptno進行分組查詢)
	COUNT(*) over (PARTITION BY deptno ORDER BY empno) AS sum_dept_add,	 ---	查詢出的部門人員數依次為前一行的求和數加上當前行的行數(若未sum則會是逐行累加的資料)
	COUNT(*) over(PARTITION BY  job) cnt_job_man	,		---查詢崗位的的人員數量	(等同於用崗位job進行分組查詢)
	COUNT(*) over (PARTITION BY job ORDER BY empno) AS sum_job_add ---查詢出崗位人員(依次為前一行的求和數加上當前行的行數(若未sum則會是逐行累加的資料)
FROM emp;

  

 

(二)、FUNCTION子句
ORACLE提供了N多個分析函式,按功能分5類

Oracle分析函式——函式列表

------------------------------------------------------------------------------------------------ 
SUM        :該函式計算組中表達式的累積和
MIN         :在一個組中的資料視窗中查詢表示式的最小值
MAX        :在一個組中的資料視窗中查詢表示式的最大值
AVG        :用於計算一個組和資料視窗內表示式的平均值。
COUNT   :對一組內發生的事情進行累積計數
-------------------------------------------------------------------------------------------------
RANK            :根據ORDER BY子句中表達式的值,從查詢返回的每一行,計算它們與其它行的相對位置
DENSE_RANK     :根據ORDER BY子句中表達式的值,從查詢返回的每一行,計算它們與其它行的相對位置
FIRST            :從DENSE_RANK返回的集合中取出排在最前面的一個值的行
LAST             :從DENSE_RANK返回的集合中取出排在最後面的一個值的行
FIRST_VALUE   :返回組中資料視窗的第一個值
LAST_VALUE     :返回組中資料視窗的最後一個值。
LAG             :可以訪問結果集中的其它行而不用進行自連線
LEAD             :LEAD與LAG相反,LEAD可以訪問組中當前行之後的行
ROW_NUMBER  :返回有序組中一行的偏移量,從而可用於按特定標準排序的行號
-------------------------------------------------------------------------------------------------
STDDEV         :計算當前行關於組的標準偏離
STDDEV_POP     :該函式計算總體標準偏離,並返回總體變數的平方根
STDDEV_SAMP  :該函式計算累積樣本標準偏離,並返回總體變數的平方根
VAR_POP         :該函式返回非空集合的總體變數(忽略null)
VAR_SAMP      :該函式返回非空集合的樣本變數(忽略null)
VARIANCE       :如果表示式中行數為1,則返回0,如果表示式中行數大於1,則返回VAR_SAMP
COVAR_POP     :返回一對錶達式的總體協方差
COVAR_SAMP  :返回一對錶達式的樣本協方差
CORR           :返回一對錶達式的相關係數
-------------------------------------------------------------------------------------------------
CUME_DIST          :計算一行在組中的相對位置
NTILE               :將一個組分為"表示式"的散列表示
PERCENT_RANK      :和CUME_DIST(累積分配)函式類似
PERCENTILE_DISC     :返回一個與輸入的分佈百分比值相對應的資料值
PERCENTILE_CONT   :返回一個與輸入的分佈百分比值相對應的資料值
RATIO_TO_REPORT   :該函式計算expression/(sum(expression))的值,它給出相對於總數的百分比
REGR_ (Linear Regression) Functions    :這些線性迴歸函式適合最小二乘法迴歸線,有9個不同的迴歸函式可使用
-------------------------------------------------------------------------------------------------
CUBE          :按照OLAP的CUBE方式進行資料統計,即各個維度均需統計
ROLLUP        :

-------------------------------------------------------------------------------------------------

示例2:查詢每個部門工資最高的員工資訊

 1、(count,rank,dense_rank,row_number)排名函式的使用及注意事項

在使用排名函式的時候需要注意以下三點:

  (1、排名函式必須有 OVER 子句。

  (2、排名函式必須有包含 ORDER BY 的 OVER 子句。

  (3、分組內從1開始排序。

-- 一般的寫法:
SELECT E.ENAME, E.JOB, E.SAL MAXSAL , E.DEPTNO
  FROM SCOTT.EMP E,
       (SELECT E.DEPTNO, MAX(E.SAL) SAL FROM SCOTT.EMP E GROUP BY E.DEPTNO) ME
 WHERE E.DEPTNO = ME.DEPTNO
   AND E.SAL = ME.SAL;         
     
--  分析函式OVER    (使用count函式用order by將相應資料分組,獲取分組編號)
SELECT ENAME,JOB,MAXSAL,DEPTNO FROM 
(SELECT     ENAME,JOB,MAX(SAL) OVER (PARTITION BY DEPTNO) AS MAXSAL,DEPTNO,
                COUNT(*) OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) AS NUM FROM EMP)
                WHERE NUM = 1;

--析函式OVER    (使用rank函式用order by將相應資料分組,獲取分組編號)
SELECT     E.ENAME,E.JOB,E.SAL,E.DEPTNO    FROM
(SELECT ENAME,JOB,SAL,RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) RANK ,DEPTNO FROM EMP) E            
WHERE  E.RANK = 1 AND NOT deptno IS NULL;

--分析函式OVER    (使用dense_rank函式用order by將相應資料分組,獲取分組編號)
SELECT     E.ENAME,E.JOB,E.SAL,E.DEPTNO    FROM
(SELECT ENAME,JOB,SAL,dense_RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) RANK ,DEPTNO FROM EMP) E            
WHERE  E.RANK = 1 AND NOT deptno IS NULL;            

--分析函式OVER    (使用row_number函式用order by將相應資料分組,獲取分組編號)
SELECT     E.ENAME,E.JOB,E.SAL,E.DEPTNO    FROM
(SELECT ENAME,JOB,SAL,row_number() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) RANK ,DEPTNO FROM EMP) E            
WHERE  E.RANK = 1 AND NOT deptno IS NULL;

 注意事項:

一般寫法與分析函式的主要區別在於:使用分析函式可以提升sql的執行效率,一般寫法是通過兩個或多個表關聯來進行查詢(存在笛卡爾積),而用分析函式則所有的查詢都在一個表中實現,大大提升了sql的查詢效率(主要體現於自身表的關聯查詢)。

row_number的用途非常廣泛,排序最好用它,它會為查詢出來的每一行記錄生成一個序號,依次排序且不會重複,注意使用row_number函式時必須要用over子句選擇對某一列進行排序才能生成序號。

rank函式用於返回結果集的分割槽內每行的排名,行的排名是相關行之前的排名數加一。簡單來說rank函式就是對查詢出來的記錄進行排名,與row_number函式不同的是,rank函式考慮到了over子句中排序欄位值相同的情況,如果使用rank函式來生成序號,over子句中排序欄位值相同的序號是一樣的,後面欄位值不相同的序號將跳過相同的排名號排下一個,也就是相關行之前的排名數加一,可以理解為根據當前的記錄數生成序號,後面的記錄依此類推。

dense_rank函式的功能與rank函式類似,dense_rank函式在生成序號時是連續的,而rank函式生成的序號有可能不連續。dense_rank函數出現相同排名時,將不跳過相同排名號,rank值緊接上一次的rank值。在各個分組內,rank()是跳躍排序,有兩個第一名時接下來就是第三名,dense_rank()是連續排序,有兩個第一名時仍然跟著第二名。

count函式用於返回結果集的分割槽內每行的排名,行的排名是相關行之前的排名數加一,count()是跳躍排序,有兩個第一名時兩個第一名的序號都為2,就沒有第一名,有兩個第二名,接下來就是第三名,dense_rank()是連續排序,有兩個第一名時仍然跟著第二名。

示例3、查詢員工資訊的同時,查詢員工工資與所在部門最低、最高工資的差額

2、(min、max)取最值函式的使用及注意事項 

--一般寫法
SELECT
E.ENAME, E.JOB,E.SAL,E.DEPTNO,
    ME.MIN_SAL MIN_SAL,
    ME.MAX_SAL MAX_SAL, E.SAL
- ME.MIN_SAL DIFF_MIN_SAL, ME.MAX_SAL - E.SAL DIFF_MAX_SAL FROM SCOTT.EMP E, (SELECT E.DEPTNO, MIN(E.SAL) MIN_SAL, MAX(E.SAL) MAX_SAL FROM SCOTT.EMP E GROUP BY E.DEPTNO) ME WHERE E.DEPTNO = ME.DEPTNO ORDER BY E.DEPTNO, E.SAL; --使用分析函式: SELECT E.ENAME, E.JOB,E.SAL,E.DEPTNO,
MIN(E.SAL) OVER(PARTITION BY E.DEPTNO) MIN_SAL, MAX(E.SAL) OVER(PARTITION BY E.DEPTNO) MAX_SAL, NVL(E.SAL - MIN(E.SAL) OVER(PARTITION BY E.DEPTNO), 0) DIFF_MIN_SAL, NVL(MAX(E.SAL) OVER(PARTITION BY E.DEPTNO) - E.SAL, 0) DIFF_MAX_SAL FROM EMP E; /*注:這裡沒有排序條件,若加上order by 排序條件, MAX() OVER(PARTITION BY .. ORDER BY .. DESC) 排序規則只能為desc,否則不起作用,將查詢到目前為止排序值最高欄位的對應值 MIN() OVER(PARTITION BY .. ORDER BY .. ASC ) 排序規則只能為asc,否則不起作用,將查詢到目前為止排序值最低的欄位的對應值, 如下:*/ SELECT E.ENAME, E.JOB,E.SAL,E.DEPTNO, MIN(E.SAL) OVER(PARTITION BY E.DEPTNO) MIN_SAL01, MAX(E.SAL) OVER(PARTITION BY E.DEPTNO) MAX_SAL01, MIN(E.SAL) OVER(PARTITION BY E.DEPTNO ORDER BY E.SAL) MIN_SAL02, MAX(E.SAL) OVER(PARTITION BY E.DEPTNO ORDER BY E.SAL) MAX_SAL02, --不起作用 MIN(E.SAL) OVER(PARTITION BY E.DEPTNO ORDER BY E.SAL DESC) MIN_SAL03, --不起作用 MAX(E.SAL) OVER(PARTITION BY E.DEPTNO ORDER BY E.SAL DESC) MAX_SAL03, MIN(E.SAL) OVER(PARTITION BY E.DEPTNO ORDER BY E.SAL ASC) MIN_SAL04, MAX(E.SAL) OVER(PARTITION BY E.DEPTNO ORDER BY E.SAL ASC) MAX_SAL04, --不起作用 NVL(E.SAL - MIN(E.SAL) OVER(PARTITION BY E.DEPTNO), 0) DIFF_MIN_SAL, NVL(MAX(E.SAL) OVER(PARTITION BY E.DEPTNO) - E.SAL, 0) DIFF_MAX_SAL FROM EMP E;