1. 程式人生 > >SQL中的視窗函式 OVER視窗函式

SQL中的視窗函式 OVER視窗函式

SQL/OR

 

與聚集函式一樣,視窗函式也針對定義的行集(組)執行聚集,但它不像聚集函式那樣每組之返回一個值,視窗函式可以為每組返回多個值。實際上,DB2中稱這種函式為聯機分析處理OLAP函式,而Oracle把它們稱為解析函式,但ISO SQL標準把它們稱為視窗函式。視窗函式一般在OLAP分析、製作報表過程中會使用到。

視窗函式:

聚合函式 over()

聚合函式 over(partition by 欄位)—分割槽

聚合函式 over(order by 欄位)--框架字句

 

本文以Oracle11g中HR模式下的Employees表為例子來試著瞭解視窗函式,

Employees表結構如下:

SQL> desc employees
 名稱                                      是否為空? 型別
 ----------------------------------------- -------- ----------------------------
 EMPLOYEE_ID                               NOT NULL NUMBER(6)
 FIRST_NAME                                         VARCHAR2(20)
 LAST_NAME                                 NOT NULL VARCHAR2(25)
 EMAIL                                     NOT NULL VARCHAR2(25)
 PHONE_NUMBER                                       VARCHAR2(20)
 HIRE_DATE                                 NOT NULL DATE
 JOB_ID                                    NOT NULL VARCHAR2(10)
 SALARY                                             NUMBER(8,2)
 COMMISSION_PCT                                     NUMBER(2,2)
 MANAGER_ID                                         NUMBER(6)
 DEPARTMENT_ID                                      NUMBER(4)

 

計算部門號位20的員工總數:

SQL> edit
  1  select first_name,department_id,count(*) over()
  2  from employees
  3* where department_id=20
SQL> /

FIRST_NAME           DEPARTMENT_ID COUNT(*)OVER()                               
-------------------- ------------- --------------                               
Michael                         20              2                               
Pat                             20              2         

 

視窗 ,函式 count(*) over() 對於查詢返回的每一行,它返回了表中所有行的計數。

在深入研究Over字句之前,一定要注意:在SQL處理中,視窗函式都是最後一步執行,而且僅位於Order by字句之前。

 

    分割槽

使用Partiton by字句定義行的分割槽或組,可以用paritition by對定義的行組計算聚集(當遇到新組的時候復位),並返回每個值(每個組中的每個成員),而不是一個用一個組表示表中的這個值的所有例項。如:

SQL> edit
  1  select first_name,department_id,count(*) over(partition by department_id) as cnt
  2  from employees
  3* order by 2
SQL> /

FIRST_NAME           DEPARTMENT_ID        CNT                                   
-------------------- ------------- ----------                                   
Jennifer                        10          1                                   
Michael                         20          2                                   
Pat                             20          2                                   
Den                             30          6                                   
Alexander                       30          6                                   
Shelli                          30          6                                   
Sigal                           30          6                                   
Guy                             30          6                                   
Karen                           30          6                                   
Susan                           40          1                                   
Matthew                         50         45    

。。。。。。。。。。

如上結果所示:對於同一個部門(同一個分割槽)的每個員工的cnt值相同,這是由於在遇到新部門之前不會重置聚集。      

 

另外partition by字句的優點是:在同一個select語句中,一個視窗函式的計算獨立於按其他列分割槽的其他視窗函式的計算。例如下面的查詢,返回每個員工、他的部門、他的部門中的員工數、他的職位以及跟他相同職位的員工數:

 

 

 1  select first_name,department_id,count(*) over (partition by department_id) as dept_cnt,
  2  job_id,
  3  count(*) over(partition by job_id) as job_cnt
  4  from employees
  5* order by 2
SQL> /

FIRST_NAME           DEPARTMENT_ID   DEPT_CNT JOB_ID        JOB_CNT             
-------------------- ------------- ---------- ---------- ----------             
Jennifer                        10          1 AD_ASST             1             
Michael                         20          2 MK_MAN              1             
Pat                             20          2 MK_REP              1             
Sigal                           30          6 PU_CLERK            5             
Alexander                       30          6 PU_CLERK            5             
Shelli                          30          6 PU_CLERK            5             
Karen                           30          6 PU_CLERK            5             
Den                             30          6 PU_MAN              1             
Guy                             30          6 PU_CLERK            5             
Susan                           40          1 HR_REP              1             
Donald                          50         45 SH_CLERK           20     

 

 

    框架字句:

當在視窗函式over字句中使用order by 字句時,就指定了兩件事:

1、分割槽中的行如何排序

2、在計算中包含哪些行

請看下面的查詢,它計算了30號員工的工資的累計和

 1  select department_id,first_name,hire_date,salary,
  2  sum(salary) over(partition by department_id) as total1,
  3  sum(salary) over() as total2,
  4  sum(salary) over(order by hire_date) as running_total
  5  from employees
  6* where department_id=30
SQL> /

DEPARTMENT_ID FIRST_NAME           HIRE_DATE          SALARY     TOTAL1         
------------- -------------------- -------------- ---------- ----------         
    TOTAL2 RUNNING_TOTAL                                                        
---------- -------------                                                        
           30 Den                  07-12月-02          11000      24900         
     24900         11000                                                        
                                                                                
           30 Alexander            18-5月 -03           3100      24900         
     24900         14100                                                        
                                                                                
           30 Sigal                24-7月 -05           2800      24900         
     24900         16900                                                        
                                                                                

DEPARTMENT_ID FIRST_NAME           HIRE_DATE          SALARY     TOTAL1         
------------- -------------------- -------------- ---------- ----------         
    TOTAL2 RUNNING_TOTAL                                                        
---------- -------------                                                        
           30 Shelli               24-12月-05           2900      24900         
     24900         19800                                                        
                                                                                
           30 Guy                  15-11月-06           2600      24900         
     24900         22400                                                        
                                                                                
           30 Karen                10-8月 -07           2500      24900         
     24900         24900                                                        
                                                                                

已選擇6行。

上面的查詢語句相當於:


 

  1  select department_id,first_name,hire_date,salary,
  2  sum(salary) over(partition by department_id) as total1,
  3  sum(salary) over() as total2,
  4  sum(salary) over(order by hire_date range between unbounded preceding and current row) as running_total
  5  from employees
  6* where department_id=30

 

 

也就說預設情況下會告訴查詢:計算所有行的和,即從當前行開始、包括它前面的所有行。對從當前行開始、包括它前面的所有行進行求和,就可以得到累計和效果了。

 

通過,框架字句允許定義資料的不同“子視窗”,以便在計算中使用,有很多方式可以指定這樣的子視窗。如:

 1  select department_id,first_name,salary,
  2  sum(salary) over (order by hire_date range between unbounded preceding and current row) as run_total1,
  3  sum(salary) over(order by hire_date rows between 1 preceding and current row) as run_total2,
  4  sum(salary) over(order by hire_date range between current row and unbounded following) as run_total3,
  5  sum(salary) over(order by hire_date rows between current row and 1 following) as run_total4
  6  from employees
  7* where department_id=30
SQL> /

DEPARTMENT_ID FIRST_NAME               SALARY RUN_TOTAL1 RUN_TOTAL2 RUN_TOTAL3  
------------- -------------------- ---------- ---------- ---------- ----------  
RUN_TOTAL4                                                                      
----------                                                                      
           30 Den                       11000      11000      11000      24900  
     14100                                                                      
                                                                                
           30 Alexander                  3100      14100      14100      13900  
      5900                                                                      
                                                                                
           30 Sigal                      2800      16900       5900      10800  
      5700                                                                      
                                                                                

DEPARTMENT_ID FIRST_NAME               SALARY RUN_TOTAL1 RUN_TOTAL2 RUN_TOTAL3  
------------- -------------------- ---------- ---------- ---------- ----------  
RUN_TOTAL4                                                                      
----------                                                                      
           30 Shelli                     2900      19800       5700       8000  
      5500                                                                      
                                                                                
           30 Guy                        2600      22400       5500       5100  
      5100                                                                      
                                                                                
           30 Karen                      2500      24900       5100       2500  
      2500                                                                      
                                                                                

已選擇6行。

 

其中:

range between unbounded preceding and current row 指定計算當前行開始、當前行之前的所有值;

rows between 1 preceding and current row 指定計算當前行的前一行開始,其範圍一直延續到當前行;

range between current row and unbounded following 指定計算從當前行開始,包括它後面的所有行;

rows between current row and 1 following 指定計算當前行和它後面的一行;

 

最後一個例子,展示 了框架字句對查詢輸出的影響,請看下面查詢:

 1  select first_name,salary,min(salary) over(order by salary) min1,
  2  max(salary) over(order by salary) max1,
  3  min(salary) over(order by salary range between unbounded preceding and unbounded following) min2,
  4  max(salary) over(order by salary range between unbounded preceding and unbounded following) max2,
  5  min(salary) over(order by salary range between current row and current row) min3,
  6  max(salary) over(order by salary range between current row and current row) max3,
  7  max(salary) over(order by salary rows between 3 preceding and 3 following) max4
  8* from employees
SQL> /

FIRST_NAME               SALARY       MIN1       MAX1       MIN2       MAX2     
-------------------- ---------- ---------- ---------- ---------- ----------     
      MIN3       MAX3       MAX4                                                
---------- ---------- ----------                                                
TJ                         2100       2100       2100       2100      24000     
      2100       2100       2400                                                
                                                                                
Steven                     2200       2100       2200       2100      24000     
      2200       2200       2400                                                
                                                                                
Hazel                      2200       2100       2200       2100      24000     
      2200       2200       2500      

 

請仔細觀察計算結果,領會子視窗的內涵;
---------------------
作者:mfkpie
來源:CSDN
原文:https://blog.csdn.net/mfkpie/article/details/16364513
版權宣告:本文為博主原創文章,轉載請附上博文連結!