一、分析函數、窗口函數一般形式
1、分析函數的形式
分析函數帶有一個開窗函數over(),包含三個分析子句:分組(partition by), 排序(order by), 窗口(rows) ,
他們的使用形式如下:分析函數名(參數) over (partition by 子句 order by 子句 rows/range.. 子句)
(注:若窗口函數內和sql語句末尾共存在兩個order by
a) order by 字段兩者一致:即sql語句中的order by子句里的內容和開窗函數over()中的order by子句里的內容一樣,
那么sql語句中的排序將先執行,分析函數在分析時就不必再排序;
b) order by 字段兩者不一致:即sql語句中的order by子句里的內容和開窗函數over()中的order by子句里的內容不一樣,
那么sql語句中的排序將最后在分析函數分析結束后執行排序。)
注意Partition by可以有多個字段。
2、以Scott用戶中的emp表,結合sum()over()簡單示例
select e.deptno, e.empno, e.ename, e.sal, sum(e.sal)over() 總收入, sum(e.sal)over(partition by e.deptno) 部門總收入,--按部門分組求和 sum(e.sal)over(order by e.empno) 員工累計收入,--按照員工編號(empno)的排序取累計收入和 sum(e.sal)over(partition by e.deptno order by e.empno) 員工部門內累計收入,--按部門(deptno)分組,同時按員工編號(empno)排序取員工部門內累計收入和 sum(e.sal)over(partition by e.deptno order by e.empno rows between unbounded preceding and unbounded following) 部門總收入2--可指定范圍,結果同上 from emp e;
累計收入求和的需要重新按empno或者empno、deptno排一下序,不然有些亂看的不是很清楚,基本常用的就是上面幾種形式
注:
--unbounded preceding and unbouned following針對當前所有記錄的前一條、后一條記錄,也就是表中的所有記錄
--unbounded:不受控制的,無限的
--preceding:在...之前
--following:在...之后
rows between unbounded preceding and unbounded following 表中的所有記錄
rows between unbounded preceding and current row 是指第一行至當前行的匯總
rows between current row and unbounded following 指當前行到最后一行的匯總
rows between 1 preceding and current row 是指當前行的上一行(rownum-1)到當前行的匯總
rows between 1 preceding and 2 following 是指當前行的上一行(rownum-1)到當前行的下兩行(rownum+2)的匯總
3、有關ROWS/RANGE窗口的例子(借鑒其他的博客)
with t as (select (case when level in (1, 2) then 1 when level in (4, 5) then 6 else level end) id from dual connect by level < 10) select id, sum(id) over(order by id) default_sum, sum(id) over(order by id range between unbounded preceding and current row) range_unbound_sum, sum(id) over(order by id rows between unbounded preceding and current row) rows_unbound_sum, sum(id) over(order by id range between 1 preceding and 2 following) range_sum, sum(id) over(order by id rows between 1 preceding and 2 following) rows_sum from t;
1、窗口子句一般和order by 子句同時使用,且如果指定了order by 子句未指定窗口子句,則默認為RANGE BETWEEN unbounded preceding AND CURRENT ROW,如上例結果集中的defult_sum等於range_unbound_sum;
2、如果分析函數沒有指定ORDER BY子句,也就不存在ROWS/RANGE窗口的計算;
3、range是邏輯窗口,是指定當前行對應值的范圍取值,列數不固定,只要行值在范圍內,對應列都包含在內,如上例中range_sum(即range 1 preceing and 2 following)例的分析結果:
當id=1時,是sum為1-1<=id<=1+2 的和,即sum=1+1+3=5(取id為1,1,3);
當id=3時,是sum為3-1<=id<=3+2 的和,即sum=3(取id為3);
當id=6時,是sum為6-1<=id<=6+2 的和,即sum=6+6+6+7+8=33(取id為6,6,6,7,8);
以此類推下去,結果如上例中所示。
4、rows是物理窗口,即根據order by 子句排序后,取的前N行及后N行的數據計算(與當前行的值無關,只與排序后的行號相關),如上例中rows_sum例結果,是取前1行和后2行數據的求和,分析上例rows_sum的結果:
當id=1(第一個1時)時,前一行沒數,后二行分別是1和3,sum=1+1+3=5;
當id=3時,前一行id=1,后二行id都為6,則sum=1+3+6+6=16;
以此類推下去,結果如上例所示。
注:行比較分析函數lead和lag無window(窗口)子句。
二、常用分析函數匯總
1、row_number() over:偽列(添加一個序號);注:此分析函數必須要加order by排序
select empno,ename,mgr,sal,deptno,row_number() over(order by empno) rn from emp;--按empno排序 select empno,ename,mgr,sal,deptno,row_number() over(partition by deptno order by empno) rn from emp;--(按部門分組,empno排序)添加一個偽列(和rownum類似) --此分析函數在對數據去重時用的比較多 select * from( select empno,ename,mgr,sal,deptno,row_number() over(partition by deptno order by empno) rn from emp) where rn = 1;--每個部門只取一條數據(當然 partition by 后面可以按需求跟多個字段,來達到你想要的篩選目的)
2、count() over():計數
select empno,ename,mgr,sal,deptno,count(*) over() from emp;--總計數 select empno,ename,mgr,sal,deptno,count(*) over(order by empno) from emp;--按照empno累計計數 select empno,ename,mgr,sal,deptno,count(*) over(partition by deptno) from emp;--按照deptno分組計數 select empno,ename,mgr,sal,deptno,count(*) over(partition by deptno order by empno) from emp;--按照deptno分組並累計計數
3、sum() over():求和
select empno,ename,mgr,sal,deptno,sum(sal) over() from emp;--總和 select empno,ename,mgr,sal,deptno,sum(sal) over(order by empno) from emp;--按empno累計求和 select empno,ename,mgr,sal,deptno,sum(sal) over(partition by deptno) from emp;--按照deptno分組求和 select empno,ename,mgr,sal,deptno,sum(sal) over(partition by deptno order by empno) from emp;--按照deptno分組並按empno累計求和
4、avg() over():求平均
select empno,ename,mgr,sal,deptno,avg(sal) over() from emp;--總平均 select empno,ename,mgr,sal,deptno,avg(sal) over(order by empno) from emp;--按照empno累計平均 select empno,ename,mgr,sal,deptno,avg(sal) over(partition by deptno) from emp;--按照deptno分組求平均 select empno,ename,mgr,sal,deptno,avg(sal) over(partition by deptno order by empno) from emp;--按照deptno分組並按empno一個個累計求平均
5、min() over();max() over():求最小最大
select empno,ename,mgr,sal,deptno ,min(sal) over() 最小金額 ,max(sal) over() 最大金額 from emp;--總最小(大) select empno,ename,mgr,sal,deptno ,min(sal) over(order by empno) 最小金額 ,max(sal) over(order by empno) 最大金額 from emp;--按empno排序並一個個遞增后的最小(大) select empno,ename,mgr,sal,deptno ,min(sal) over(partition by deptno) 最小金額 ,max(sal) over(partition by deptno) 最大金額 from emp;--按deptno分組后的最小(大) select empno,ename,mgr,sal,deptno ,min(sal) over(partition by deptno order by empno) 最小金額 ,max(sal) over(partition by deptno order by empno) 最大金額 from emp;--組內、遞增累計后的最小(大)
6、rank() over():跳躍排序;dense_rank():連續排序;注:此分析函數同row_number() over()必須要加order by排序
select empno,ename,mgr,sal,deptno ,rank() over(order by sal desc) 跳躍排序 ,dense_rank() over(order by sal desc) 連續排序 from emp;--按sal金額排名 select empno,ename,mgr,sal,deptno ,rank() over(partition by deptno order by sal desc) 跳躍排序 ,dense_rank() over(partition by deptno order by sal desc) 連續排序 from emp;--按deptno分組,組內、金額排名
7、ntile(n) over():將數據等分成n組(不夠等分的按順序添加到每個組內);注:必須要加order by
select empno,ename,mgr,sal,deptno,ntile(3) over(order by empno) from emp;--將數據等分3組(不夠等分的按順序添加到每個組內) select empno,ename,mgr,sal,deptno,ntile(3) over(partition by deptno order by empno) from emp;--組內再將數據均分3組
8、first_value() over():取對應第一條記錄;last_value() over():取對應最后一條記錄(可加 ignore nulls 空值填充)向下(上)找最近的不為空的值
還有:nth_value(value any, nth integer):返回窗口框架中的指定值,如nth_value(salary,2),則表示返回字段salary的第二個窗口函數值
select empno,ename,mgr,sal,deptno ,first_value(sal ignore nulls) over() 整表sal的第一條記錄 ,last_value(sal ignore nulls) over() 整表sal的最后一條記錄 from emp; select empno,ename,mgr,sal,deptno ,first_value(ename) over(order by empno) 第一條ename記錄 ,last_value(ename) over(order by empno) 最后一條ename記錄 from emp;--按empno順序第一、最后一條數據 select empno,ename,mgr,sal,deptno ,first_value(sal) over(partition by deptno) 第一條記錄 ,last_value(sal) over(partition by deptno) 最后一條記錄 from emp;--部門組內數據第一、最后一條 select empno,ename,mgr,sal,deptno ,first_value(sal) over(partition by deptno order by empno) 第一條記錄 ,last_value(sal) over(partition by deptno order by empno) 最后一條記錄 from emp;--部門組內、遞增數據第一、最后一條
9、keep (dense_rank first/last order by ...)over():配合max()/min()取集合內第一或最后一條
select empno,ename,mgr,sal,deptno ,max(sal) keep(dense_rank first order by sal desc)over() 第一條記錄 ,max(sal) keep(dense_rank last order by sal desc)over() 最后一條記錄 from emp;--取集合內第一或最后一條 select empno,ename,mgr,sal,deptno ,max(sal) keep(dense_rank first order by sal desc)over(partition by deptno) 第一條記錄 ,max(sal) keep(dense_rank last order by sal desc)over(partition by deptno) 最后一條記錄 from emp;--組內排序后第一或最后一條
10、lag(column_name,n,若首行無填充默認為null) over() :取出前n行數據;lead() over() :取出前(后)第n行數據;注:必須要加order by排序(11g中支持ignore nulls)
select empno,ename,mgr,sal,deptno ,lag(sal,1) over(order by empno) sal的上一條記錄 ,lead(sal,1) over(order by empno) sal的下一條記錄 from emp;--取出前(后)第1行數據 select empno,ename,mgr,sal,deptno ,lag(sal,2,0) over(partition by deptno order by empno) sal的上一條記錄 ,lead(sal,2,0) over(partition by deptno order by empno) sal的下一條記錄 from emp;--取出組內前(后)第2行數據
11、ratio_to_report(a) over(partition by b) :求按照b分組后a的值在所屬分組中總值的占比,a的值必須為數值或數值型字段;注:禁用order by
簡單理解就是a/b
select empno,ename,mgr,sal,deptno ,ratio_to_report(1) over() 比上總行數 ,ratio_to_report(1) over(partition by deptno) 比上組內行數 from emp;--1/總(組內)行數 select empno,ename,mgr,sal,deptno ,ratio_to_report(sal) over() sal占總比 ,ratio_to_report(sal) over(partition by deptno) sal組內占比 from emp;--金額占比
12、percent_rank() over():(所在序號-1)/(總行數-1) 注:必須要加order by排序
13、cume_dist() over() :所在組排名序號除以該組所有的行數,注意對於重復行,計算時取重復行中的最后一行的位置
select empno,ename,mgr,sal,deptno,cume_dist() over(order by sal) 行數總比 from emp; select empno,ename,mgr,sal,deptno,cume_dist() over(partition by deptno order by sal) 組內行數比 from emp;
14、precentile_cont( x ) within group(order by ...) over():over()中partition by可選,order by 不可選
x為輸入的百分比,是0-1之間的一個小數,返回該百分比位置的數據,若沒有則取上下對應兩個值的平均值:
select empno,ename,mgr,sal,deptno ,percentile_cont(0.5) within group(order by sal) over() Percentile_Cont ,percent_rank() over(order by sal) Percent_Rank from emp; --Percentile_Cont輸入百分比為0.5,則他在對應Percent_Rank:0.46;0.53之間,值就取他兩對應值的平均數(1500+1600)/2=1550下面同理 select empno,ename,mgr,sal,deptno ,percentile_cont(0.5) within group(order by sal) over(partition by deptno) Percentile_Cont ,percent_rank() over(partition by deptno order by sal) Percent_Rank from emp;
15、percentile_disc() within group(order by ...) over():返回一個與輸入的分布百分比值相對應的數據值,如果沒有正好對應的數據值,就取大於該分布值的下一個值(好像要四舍五入)。
注意:本函數與percentile_cont的區別在找不到對應的分布值時返回的替代值的計算方法不同
select empno,ename,mgr,sal ,deptno,percentile_disc(0.7) within group(order by sal) over() Percentile_Cont ,percent_rank() over(order by sal) Percent_Rank from emp; select empno,ename,mgr,sal,deptno ,percentile_disc(0.5) within group(order by sal) over(partition by deptno) Percentile_Cont ,percent_rank() over(partition by deptno order by sal) Percent_Rank from emp;
16、stddev() over():計算樣本標准差,只有一行數據時返回0,partition by 可選,order by 可選
stddev_samp() over():計算樣本標准差,只有一行數據時返回null,partition by 可選,order by 可選
stddev_pop() over():計算總體標准差,partition by 可選,order by 可選
select empno,ename,mgr,sal,deptno ,stddev(sal) over() 所有記錄樣本標准差1 ,stddev_samp(sal) over() 所有記錄樣本標准差2 ,stddev_pop(sal) over() 所有記錄總體標准差 from emp; select empno,ename,mgr,sal,deptno ,stddev(sal) over(order by empno) 累加的樣本標准差1 ,stddev_samp(sal) over(order by empno) 累加的樣本標准差2 ,stddev_pop(sal) over(order by empno) 累加的總體標准差 from emp; select empno,ename,mgr,sal,deptno ,stddev(sal) over(partition by deptno) 組內樣本標准差1 ,stddev_samp(sal) over(partition by deptno) 組內樣本標准差2 ,stddev_pop(sal) over(partition by deptno) 組內總體標准差 from emp; select empno,ename,mgr,sal,deptno ,stddev(sal) over(partition by deptno order by empno) 計算組內累加的樣本標准差1 ,stddev_samp(sal) over(partition by deptno order by empno) 計算組內累加的樣本標准差2 ,stddev_pop(sal) over(partition by deptno order by empno) 計算組內累加的樣本總體標准差 from emp;
17、variance() over():計算樣本方差,只有一行數據時返回0,partition by 可選,order by 可選
var_samp() over():計算樣本方差,只有一行數據時返回null,partition by 可選,order by 可選
var_pop() over():計算總體方差,partition by 可選,order by 可選
select empno,ename,mgr,sal,deptno ,variance(sal) over() 所有記錄樣本方差1 ,var_samp(sal) over() 所有記錄樣本方差2 ,var_pop(sal) over() 所有記錄總體方差 from emp; select empno,ename,mgr,sal,deptno ,variance(sal) over(order by empno) 累加的樣本方差1 ,var_samp(sal) over(order by empno) 累加的樣本方差2 ,var_pop(sal) over(order by empno) 累加的總體方差 from emp; select empno,ename,mgr,sal,deptno ,variance(sal) over(partition by deptno) 組內樣本方差1 ,var_samp(sal) over(partition by deptno) 組內樣本方差2 ,var_pop(sal) over(partition by deptno) 組內總體方差 from emp; select empno,ename,mgr,sal,deptno ,variance(sal) over(partition by deptno order by empno) 計算組內累加的樣本方差1 ,var_samp(sal) over(partition by deptno order by empno) 計算組內累加的樣本方差2 ,var_pop(sal) over(partition by deptno order by empno) 計算組內累加的樣本總體方差 from emp;
--stddev()=sqrt(variance()) sqrt()--求開方
--stddev_samp()=sqrt(var_samp())
--stddec_pop=sqrt(var_pop())
17、covar_samp over():返回一對表達式的樣本協方差,partition by 可選,order by 可選
covar_pop over(): 返回一堆表達式的總體協方差,partition by 可選,order by 可選
18、corr() over() :返回一對表達式的相關系數,partition by 可選,order by 可選
19、REGR_ (Linear Regression) Functions:這些線性回歸函數適合最小二乘法回歸線,有9個不同的回歸函數可使用
(注:此為學習記錄筆記,僅供參考若有問題請指正,后續補充......)
參考原文:http://www.blogjava.net/pengpenglin/archive/2008/06/25/210536.html
參考原文:https://blog.csdn.net/huozhicheng/article/details/5843782/
參考原文:https://blog.csdn.net/haiross/article/details/15336313
參考原文:https://blog.csdn.net/cc_0101/article/details/80884076
參考原文:https://blog.csdn.net/richieruan/article/details/52712447?locationNum=6