轉自http://hi.baidu.com/edgar108/blog/item/e24c7fd66b0817d7a144dfc8.html
我以oracle中的emp 和dept表爲例,講一下開窗函數。
假如,現在有這樣的要求:查出所有的員工的名字ename,薪水sal 以及他的薪水佔說有員工薪水的比例。
一開始,我們的思路可能是這樣:
select ename ,sal ,sal/sum(sal) from emp;
但是這樣寫是不對的,sum()是一個單行統計函數,只返回一個值,不能和其他字段同時出現。
解決辦法就是使用開窗函數over()
select ename
,sal ,sal/sum(sal) over() as percent from emp;
查詢結果:
ENAME
SAL
PERCENT
---------- ---------- ----------
SMITH
800 .027562446
ALLEN
1600 .055124892
WARD
1250 .043066322
JONES
2975 .102497847
MARTIN
1250 .043066322
BLAKE
2850 .098191214
CLARK
2450 .084409991
SCOTT
3000 .103359173
KING
5000 .172265289
TURNER
1500 .051679587
ADAMS
1100 .037898363
ENAME
SAL
PERCENT
---------- ---------- ----------
JAMES
950 .032730405
FORD
3000 .103359173
MILLER
1300 .044788975
已選擇14行。
上面的over是指把前面的函數(本例中是sum())當成開窗函數而不是統計函數,SQL標準允許講所有的統計函數
用作開窗函數,使用over關鍵字來區分這兩種用法。
上面的“sum(sal) over()”的意思是,對於每一條記錄,都去計算一次sal的和。如果over關鍵字後的括號中的選項爲空,
把上面的sql改進一下:
select ename
,sal ,'0'||round(sal/sum(sal) over(),3) as percent from
emp;
查詢結果:
ENAME
SAL PERCENT
---------- ----------
-----------------------------------------
SMITH
800 0.028
ALLEN
1600 0.055
WARD
1250 0.043
JONES
2975 0.102
MARTIN
1250 0.043
BLAKE
2850 0.098
CLARK
2450 0.084
SCOTT
3000 0.103
KING
5000 0.172
TURNER
1500 0.052
ADAMS
1100 0.038
ENAME
SAL PERCENT
---------- ----------
-----------------------------------------
JAMES
950 0.033
FORD
3000 0.103
MILLER
1300 0.045
已選擇14行。
如果現在像查詢每個員工的姓名ename,工資sal,以及他的工資佔他所在部門的比例,按照上面的思路,這次要這樣寫:
select ename,deptno,sal,'0'|| round(sal/sum(sal) over(partition by deptno),3) from emp;
如果需要對sal排序,再partition by deptno 後面 再加上order by sal:
select ename,deptno,sal,'0'|| round(sal/sum(sal) over(partition by deptno order by sal),3) from emp;
ORDER BY 的完整語法爲
ORDER BY 字段名 RANGE|ROWS BETWEEN 邊界規則1 AND 邊界規則2
RANGE 表示 按照值的範圍進行範圍的定義,而 ROWS 表示按照行的範圍進行範圍的定義
邊界規則的取值見下表:
可取值 說明 示例
CURRENT ROW 當前行
N PRECEDING 前N行 2 PRECEDING
UNBOUNDED PRECEDING 一直到第一條記錄
N FOLLOWING 後N行 2 FOLLOWING
UNBOUNDED FOLLOWING 一直到最後一條記錄
但是,如果這樣寫,會報錯:
select
ename,deptno,sal,'0'|| round(sal/sum(sal) over(order by sal
partition by deptno ),3) from emp;可能 order by不能寫在partition
by的前面。
如果現在按照員工的姓名排序,並計算工資的累加和:
select ename
,sal ,sum(sal) over(order by sal rows between unbounded preceding
and current row) as result from emp;
order by sal
rows between unbounded preceding and current row 的意思是:
按照sal進行排序,然後計算從第一行(unbounded preceding)到當前行
(current row)的和,這樣的結果就是按照工資進行排序的工作值的累加和。
因爲ROWS 表示按照行的範圍進行範圍的定義,所以計算從第一行到當前行的累加和。
如果把ROWS換成 RANGE :
select ename ,sal ,sum(sal) over(order by sal range between unbounded preceding and current row) as result from emp;
ENAME
SAL
RESULT
---------- ---------- ----------
SMITH
800
800
JAMES
950
1750 (800+950)
ADAMS
1100
2850 (800+950+1100)
WARD
1250
5350
MARTIN
1250
5350
MILLER
1300
6650
TURNER
1500
8150
ALLEN
1600
9750
CLARK
2450
12200
BLAKE
2850
15050
JONES
2975
18025
ENAME
SAL
RESULT
---------- ---------- ----------
SCOTT
3000
24025
FORD
3000
24025
KING
5000
29025
已選擇14行。
RANGE 表示
按照值的範圍進行範圍的定義 ,在計算累加和的過程中,如果遇到相同的值(本例中爲sal),則計算所有的相同值同時累加
(本例中SCOTT,FORD的sal全是3000,所以值是
18025+3000+3000=24025)
select ename ,sal ,sum(sal) over(order by sal rows between 2 preceding and 2 following) as result from emp;
ENAME
SAL
RESULT
---------- ---------- ----------
SMITH
800
2850 (800+950+1100)
JAMES
950
4100
ADAMS
1100
5350
WARD
1250
5850
MARTIN
1250
6400
MILLER
1300
6900
TURNER
1500
8100 (1250+1300+1500+1600+2450)
ALLEN
1600
9700
CLARK
2450
11375
BLAKE
2850
12875
JONES
2975
14275 (2450+2850+2975+3000+3000)
ENAME
SAL
RESULT
---------- ---------- ----------
SCOTT
3000
16825
FORD
3000
13975
KING
5000
11000 (3000+3000+5000)
已選擇14行。
sum(sal)
over(order by sal rows between 2 preceding and 2 following)
按照sal進行排序,然後計算從當前行前兩行(2 preceding) 到 當前行後兩行(2
following)的累加和
對於第1行到第2行(n=2),“前2行”是不存在或不完整的,所以按照前兩行不存在或不完整來計算,最後2行類似。
select ename ,sal ,sum(sal) over(order by sal rows between 1 following and 3 following) as result from emp;
ENAME
SAL
RESULT
---------- ---------- ----------
SMITH
800
3300 (950+1100+1250)
JAMES
950
3600
ADAMS
1100
3800
WARD
1250
4050
MARTIN
1250
4400
MILLER
1300
5550
TURNER
1500
6900
ALLEN
1600
8275
CLARK
2450
8825
BLAKE
2850
8975
JONES
2975
11000
ENAME
SAL
RESULT
---------- ---------- ----------
SCOTT
3000
8000
FORD
3000
5000
KING
5000
(後面沒有數據了,所以是NULL)
已選擇14行。
計算的某一列後1行到後3行的值
select ename
,sal ,sum(sal) over(order by sal range between unbounded preceding
and current row) as result from emp;
與
select ename ,sal ,sum(sal) over(order by sal) as result from
emp;
是等價的。
也就是說 range
between unbounded preceding and current row
是默認的定位方式。
select ename ,sal ,count(*) over(order by sal desc rows between unbounded preceding and current row) as result from emp;
ENAME
SAL
RESULT
---------- ---------- ----------
KING
5000
1
FORD
3000
2
SCOTT
3000
3
JONES
2975
4
BLAKE
2850
5
CLARK
2450
6
ALLEN
1600
7
TURNER
1500
8
MILLER
1300
9
WARD
1250
10
MARTIN
1250
11
ENAME
SAL
RESULT
---------- ---------- ----------
ADAMS
1100
12
JAMES
950
13
SMITH
800
14
已選擇14行。
order by sal desc rows between unbounded preceding and current row
表示按照sal的降序排列,計算從第一行到當前行的個數,所以這個可以看作員工工資的排名。