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
版權宣告:本文為博主原創文章,轉載請附上博文連結!