Oracle分析函數簡析


oracle的分析函數over(Partition by...)

Sql代碼  

    over(Partition by...) 一個超級牛皮的ORACLE特有函數。  

最近工作中才接觸到這個功能強大而靈活的函數。  

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

一:分析函數over  

Oracle從8.1.6開始提供分析函數,分析函數用於計算基於組的某種聚合值,它和聚合函數的不同之處是  

對於每個組返回多行,而聚合函數對於每個組只返回一行。   

下面通過幾個例子來說明其應用。 

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

2,rank over 說明

排序:

---rank()over(order by 列名 排序)的結果是不連續的,如果有4個人,其中有3個是並列第1名,那么最后的排序結果結果如:1 1 1 4
select scoreid, studentid,COURSENAME,totalexamscore ,
rank()over(order by TOTALEXAMSCORE desc)orderbyNum
from SCORECOURSE a ,COURSESCORE b
where a.SCORECOURSEID = b.SCORECOURSEID

---dense_rank()over(order by 列名 排序)的結果是連續的,如果有4個人,其中有3個是並列第1名, 那么最后的排序結果如:1 1 1 2
select scoreid, studentid,COURSENAME,totalexamscore ,
dense_rank()over(order by TOTALEXAMSCORE desc)orderbyNum
from SCORECOURSE a ,COURSESCORE b
where a.SCORECOURSEID = b.SCORECOURSEID

 

----rank () OVER (PARTITION BY 列名 ORDER BY 列名 排序)使用分區方式獲取每門課程的最高分
SELECT *
  FROM (SELECT scoreid, studentid, coursename, TOTALEXAMSCORE,
               rank () OVER (PARTITION BY coursename ORDER BY TOTALEXAMSCORE DESC)orderbynum
          FROM scorecourse a, coursescore b
         WHERE a.scorecourseid = b.scorecourseid and studentID = 'xxxxx')
 WHERE orderbynum < 2

-----使用over實現成績求和
-----SUM (totalexamscore) OVER (ORDER BY studentid) sum1  實現的是連續求和,如第一個學生的總評成績是30,則sum1就展示為30,到第二個學生成績出現的時候,則會依次累加
-----SUM (totalexamscore) OVER () sum2 就相當於是單純的求和,和直接使用sum是一致的
SELECT scoreid, studentid, totalexamscore,
       SUM (totalexamscore) OVER (ORDER BY studentid) sum1,
       SUM (totalexamscore) OVER () sum2
  FROM coursescore
注:這個案例想了很久也沒想到很直觀的描述,還請大家親自去測試一下吧!!

語法:
rank() over (order by 排序字段 順序)
rank() over (partition by 分組字段 order by 排序字段 順序)

 

1.順序:asc|desc  名次與業務相關:
  示例:求優秀學員,成績:降序  遲到次數:升序
2.分區字段:根據什么字段進行分區。

問題:分區與分組有什么區別?
•分區只是將原始數據進行名次排列(記錄數不變),
•分組是對原始數據進行聚合統計(記錄數變少,每組返回一條)。

注意:使用rank()over(order by 排序字段 順序)排序的時候,空值是最大的
(如果排序字段為null,可能造成在排序時將null字段排在最前面,影響排序的正確性。
所以建議將dense_rank()over(order by 列名 排序)改為dense_rank()over(order by 列名 排序 nulls last)
這樣只要排序字段為null,就會放在最后,而不會影響排序結果).

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM