oracle的分析函數over 及開窗函數

轉:http://www.2cto.com/database/201310/249722.html
oracle的分析函數over 及開窗函數  
一:分析函數over  
Oracle從8.1.6開始提供分析函數,分析函數用於計算基於組的某種聚合值,它和聚合函數的不一樣之處是  
對於每一個組返回多行,而聚合函數對於每一個組只返回一行。   
下面經過幾個例子來講明其應用。                                         
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
1:統計某商店的營業額。         
      date       sale 
      1           20 
      2           15 
      3           14 
      4           18 
      5           30 
     規則:按天統計:天天都統計前面幾天的總額 
     獲得的結果: 
     DATE   SALE       SUM 
     ----- -------- ------ 
     1      20        20           --1天            
     2      15        35           --1天+2天            
     3      14        49           --1天+2天+3天            
     4      18        67            .           
     5      30        97            . 
        
2:統計各班成績第一名的同窗信息 
     NAME   CLASS S                          
     ----- ----- ----------------------  
     fda    1      80                      
     ffd    1      78                      
     dss    1      95                      
     cfe    2      74                      
     gds    2      92                      
     gf     3      99                      
     ddd    3      99                      
     adf    3      45                      
     asdf   3      55                      
     3dd    3      78               
      
     經過:    
     -- 
     select * from                                                                        
     (                                                                             
     select name ,class,s,rank()over(partition by class order by s desc ) mm from t2 
     )                                                                             
     where mm=1  
     -- 
     獲得結果: 
     NAME   CLASS S                       MM                                                                                         
     ----- ----- ---------------------- ----------------------  
     dss    1      95                      1                       
     gds    2      92                      1                       
     gf     3      99                      1                       
     ddd    3      99                      1           
      
     注意: 
     1.在求第一名成績的時候,不能用row_number(),由於若是同班有兩個並列第一,row_number()只返回一個結果           
     2.rank()和dense_rank()的區別是: 
       --rank()是跳躍排序,有兩個第二名時接下來就是第四名 
       --dense_rank()l是連續排序,有兩個第二名時仍然跟着第三名 
        
        
3.分類統計 (並顯示信息) 
     A   B   C                       
     -- -- ----------------------  
     m   a   2                       
     n   a   3                       
     m   a   2                       
     n   b   2                       
     n   b   1                       
     x   b   3                       
     x   b   2                       
     x   b   4                       
     h   b   3  
    select a,c, sum (c)over(partition by a) from t2                 
    獲得結果: 
    A   B   C        SUM (C)OVER(PARTITIONBYA)       
    -- -- ------- ------------------------  
    h   b   3        3                         
    m   a   2        4                         
    m   a   2        4                         
    n   a   3        6                         
    n   b   2        6                         
    n   b   1        6                         
    x   b   3        9                         
    x   b   2        9                         
    x   b   4        9                         
     
    若是用 sum group by 則只能獲得 
    A   SUM (C)                             
    -- ----------------------  
    h   3                       
    m   4                       
    n   6                       
    x   9                       
    沒法獲得B列值        
     
===== 
select * from test 
   
數據: 
A B C  
1 1 1  
1 2 2  
1 3 3  
2 2 5  
3 4 6  
   
   
---將B欄位值相同的對應的C 欄位值加總 
select a,b,c, SUM (C) OVER (PARTITION BY B) C_Sum 
from test 
   
A B C C_SUM  
1 1 1 1  
1 2 2 7  
2 2 5 7  
1 3 3 3  
3 4 6 6  
   
---若是不須要已某個欄位的值分割,那就要用 null 
   
eg: 就是將C的欄位值summary 放在每行後面 
   
select a,b,c, SUM (C) OVER (PARTITION BY null ) C_Sum 
from test 
   
A B C C_SUM  
1 1 1 17  
1 2 2 17  
1 3 3 17  
2 2 5 17  
3 4 6 17 
   
求我的工資佔部門工資的百分比  
   
SQL> select * from salary; 
   
NAME DEPT SAL 
---------- ---- ----- 
a 10 2000 
b 10 3000 
c 10 5000 
d 20 4000 
   
SQL> select name ,dept,sal,sal*100/ sum (sal) over(partition by dept) percent from salary; 
   
NAME DEPT SAL PERCENT 
---------- ---- ----- ---------- 
a 10 2000 20 
b 10 3000 30 
c 10 5000 50 
d 20 4000 100 
   
二:開窗函數            
       開窗函數指定了分析函數工做的數據窗口大小,這個數據窗口大小可能會隨着行的變化而變化,舉例以下:  
1:      
    over( order by salary) 按照salary排序進行累計, order by 是個默認的開窗函數 
    over(partition by deptno)按照部門分區 
2: 
   over( order by salary range between 5 preceding and 5 following) 
    每行對應的數據窗口是以前行幅度值不超過5,以後行幅度值不超過5 
    例如:對於如下列 
      aa 
     
     
     
     
     
     
     
     
     
     
      
    sum (aa)over( order by aa range between 2 preceding and 2 following) 
    得出的結果是 
             AA                       SUM 
             ---------------------- -------------------------------------------------------  
             1                       10                                                       
             2                       14                                                       
             2                       14                                                       
             2                       14                                                       
             3                       18                                                       
             4                       18                                                       
             5                       22                                                       
             6                       18                                                                 
             7                       22                                                                 
             9                       9                                                                  
                
    就是說,對於aa=5的一行 , sum 爲   5-1<=aa<=5+2 的和 
    對於aa=2來講 , sum =1+2+2+2+3+4=14     ; 
    又如 對於aa=9 ,9-1<=aa<=9+2 只有9一個數,因此 sum =9    ; 
                 
3:其它: 
      over( order by salary rows between 2 preceding and 4 following) 
           每行對應的數據窗口是以前2行,以後4行  
4:下面三條語句等效:            
      over( order by salary rows between unbounded preceding and unbounded following) 
           每行對應的數據窗口是從第一行到最後一行,等效: 
      over( order by salary range between unbounded preceding and unbounded following) 
            等效 
      over(partition by null
   
經常使用的分析函數以下所列: 
   
row_number() over(partition by ... order by ...) 
rank() over(partition by ... order by ...) 
dense_rank() over(partition by ... order by ...) 
count () over(partition by ... order by ...) 
max () over(partition by ... order by ...) 
min () over(partition by ... order by ...) 
sum () over(partition by ... order by ...) 
avg () over(partition by ... order by ...) 
first_value() over(partition by ... order by ...) 
last_value() over(partition by ... order by ...) 
lag() over(partition by ... order by ...) 
lead() over(partition by ... order by ...) 
   
示例 
SQL> select type,qty from test; 
   
TYPE QTY 
---------- ---------- 
1 6 
2 9 
   
  SQL> select type,qty,to_char(row_number() over(partition by type order by qty))|| '/' ||to_char( count (*) over(partition by type)) as cnt2 from test; 
   
TYPE QTY CNT2  
---------- ---------- ------------ 
3 1/2 
1 6 2/2 
2 5 1/3 
7 2/3  
2 9 3/3 
   
  SQL> select * from test; 
---------- ------------------------------------------------- 
1 11111 
2 22222 
3 33333 
4 44444 
   
SQL> select t.id,mc,to_char(b.rn)|| '/' ||t.id)e 
2 from test t, 
  ( select rownum rn from ( select max (to_number(id)) mid from test) connect by rownum <=mid ))L 
4 where b.rn<=to_number(t.id) 
order by id 
   
ID MC TO_CHAR(B.RN)|| '/' ||T.ID 
--------- -------------------------------------------------- --------------------------------------------------- 
1 11111 1/1 
2 22222 1/2 
2 22222 2/2 
3 33333 1/3 
3 33333 2/3 
3 33333 3/3 
  44444 1/4 44444 2/4 
4 44444 3/4CNOUG4 44444 4/4 
   
10 rows selected 
   
*******************************************************************

 

  
關於partition by  
  
這些都是分析函數,好像是8.0之後纔有的 row_number()和rownum差很少,功能更強一點(能夠在各個分組內從1開時排序) rank()是跳躍排序,有兩個第二名時接下來就是第四名(一樣是在各個分組內) dense_rank()l是連續排序,有兩個第二名時仍然跟着第三名。相比之下row_number是沒有重複值的 lag(arg1,arg2,arg3): arg1是從其餘行返回的表達式 arg2是但願檢索的當前行分區的偏移量。是一個正的偏移量,時一個往回檢索之前的行的數目。 arg3是在arg2表示的數目超出了分組的範圍時返回的值。  
  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1. 
select deptno,row_number() over(partition by deptno order by sal) from emp order by deptno; 
2. 
select deptno,rank() over (partition by deptno order by sal) from emp order by deptno; 
3. 
select deptno,dense_rank() over(partition by deptno order by sal) from emp order by deptno; 
4. 
select deptno,ename,sal,lag(ename,1, null ) over(partition by deptno order by ename) from emp ord er by deptno; 
5. 
select deptno,ename,sal,lag(ename,2, 'example' ) over(partition by deptno order by ename) from em p 
order by deptno; 
6. 
select deptno, sal, sum (sal) over(partition by deptno) from emp; --每行記錄後都有總計值  select deptno, sum(sal) from emp group by deptno; 
7. 求每一個部門的平均工資以及每一個人與所在部門的工資差額 
   
select deptno,ename,sal , 
      round( avg (sal) over(partition by deptno)) as dept_avg_sal,  
      round(sal- avg (sal) over(partition by deptno)) as dept_sal_diff 
from emp;
相關文章
相關標籤/搜索