一:分析函數overOracle從8.1.6開始提供分析函數,分析函數用於計算基於組的某種聚合值,它和聚合函數的不同之處是對於每個組返回多行,而聚合函數對於每個組只返回一行。 1、分析函數和聚合函數的不同之處: 分析函數和聚合函數很多是同名的,意思也一樣,只是聚合函數用group 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;
oracle分析函數-----實驗
--1、GROUP BY子句
--CREATE TEST TABLE AND INSERT TEST DATA.
create table students
(id number(15,0),
area varchar2(10),
stu_type varchar2(2),
score number(20,2));
insert into students values(1, '111', 'g', 80 );
insert into students values(1, '111', 'j', 80 );
insert into students values(1, '222', 'g', 89 );
insert into students values(1, '222', 'g', 68 );
insert into students values(2, '111', 'g', 80 );
insert into students values(2, '111', 'j', 70 );
insert into students values(2, '222', 'g', 60 );
insert into students values(2, '222', 'j', 65 );
insert into students values(3, '111', 'g', 75 );
insert into students values(3, '111', 'j', 58 );
insert into students values(3, '222', 'g', 58 );
insert into students values(3, '222', 'j', 90 );
insert into students values(4, '111', 'g', 89 );
insert into students values(4, '111', 'j', 90 );
insert into students values(4, '222', 'g', 90 );
insert into students values(4, '222', 'j', 89 );
commit;
--A、GROUPING SETS
select id,area,stu_type,sum(score) score
from students
group by grouping sets((id,area,stu_type),(id,area),id)
order by id,area,stu_type;
/*--------理解grouping sets
select a, b, c, sum( d ) from t
group by grouping sets ( a, b, c )
等效於
select * from (
select a, null, null, sum( d ) from t group by a
union all
select null, b, null, sum( d ) from t group by b
union all
select null, null, c, sum( d ) from t group by c
)
*/
--B、ROLLUP
select id,area,stu_type,sum(score) score
from students
group by rollup(id,area,stu_type)
order by id,area,stu_type;
/*--------理解rollup
select a, b, c, sum( d )
from t
group by rollup(a, b, c);
等效於
select * from (
select a, b, c, sum( d ) from t group by a, b, c
union all
select a, b, null, sum( d ) from t group by a, b
union all
select a, null, null, sum( d ) from t group by a
union all
select null, null, null, sum( d ) from t
)
*/
--C、CUBE
select id,area,stu_type,sum(score) score
from students
group by cube(id,area,stu_type)
order by id,area,stu_type;
/*--------理解cube
select a, b, c, sum( d ) from t
group by cube( a, b, c)
等效於
select a, b, c, sum( d ) from t
group by grouping sets(
( a, b, c ),
( a, b ), ( a ), ( b, c ),
( b ), ( a, c ), ( c ),
() )
*/
--D、GROUPING
/*從上面的結果中我們很容易發現,每個統計數據所對應的行都會出現null,
如何來區分到底是根據那個欄位做的彙總呢,grouping函數判斷是否合計列!*/
select decode(grouping(id),1,'all id',id) id,
decode(grouping(area),1,'all area',to_char(area)) area,
decode(grouping(stu_type),1,'all_stu_type',stu_type) stu_type,
sum(score) score
from students
group by cube(id,area,stu_type)
order by id,area,stu_type;
--2、OVER()函數的使用
--1、RANK()、DENSE_RANK() 的、ROW_NUMBER()、CUME_DIST()、MAX()、AVG()
break on id skip 1
select id,area,score from students order by id,area,score desc;
select id,rank() over(partition by id order by score desc) rk,score from students;
--允許併列名次、名次不間斷
select id,dense_rank() over(partition by id order by score desc) rk,score from students;
--即使SCORE相同,ROW_NUMBER()結果也是不同
select id,row_number() over(partition by ID order by SCORE desc) rn,score from students;
select cume_dist() over(order by id) a, --該組最大row_number/所有記錄row_number
row_number() over (order by id) rn,id,area,score from students;
select id,max(score) over(partition by id order by score desc) as mx,score from students;
select id,area,avg(score) over(partition by id order by area) as avg,score from students; --註意有無order by的區別
--按照ID求AVG
select id,avg(score) over(partition by id order by score desc rows between unbounded preceding
and unbounded following ) as ag,score from students;
--2、SUM()
select id,area,score from students order by id,area,score desc;
select id,area,score,
sum(score) over (order by id,area) 連續求和, --按照OVER後邊內容彙總求和
sum(score) over () 總和, -- 此處sum(score) over () 等同於sum(score)
100*round(score/sum(score) over (),4) "份額(%)"
from students;
select id,area,score,
sum(score) over (partition by id order by area ) 連id續求和, --按照id內容彙總求和
sum(score) over (partition by id) id總和, --各id的分數總和
100*round(score/sum(score) over (partition by id),4) "id份額(%)",
sum(score) over () 總和, -- 此處sum(score) over () 等同於sum(score)
100*round(score/sum(score) over (),4) "份額(%)"
from students;
--4、LAG(COL,n,default)、LEAD(OL,n,default) --取前後邊N條數據
select id,lag(score,1,0) over(order by id) lg,score from students;
select id,lead(score,1,0) over(order by id) lg,score from students;
--5、FIRST_VALUE()、LAST_VALUE()
select id,first_value(score) over(order by id) fv,score from students;
select id,last_value(score) over(order by id) fv,score from students;