深入淺出談開窗函數(一)


        在開窗函數出現之前存在着非常多用 SQL 語句非常難解決的問題,非常多都要通過復雜的相關子查詢或者存儲過程來完畢。為了解決這些問題,在2003年ISO  SQL標准增加了開窗函數,開窗函數的使用使得這些經典的難題能夠被輕松的解決。眼下在 MSSQLServer、Oracle、DB2 等主流數據庫中都提供了對開窗函數的支持,只是非常遺憾的是 MYSQL 臨時還未對開窗函數給予支持。 

為了更加清楚地理解,我們來建表並進行相關的查詢(截圖為MSSQLServer中的結果)

        MYSQL,MSSQLServer,DB2: 
        

CREATE TABLE T_Person 
(
	FName VARCHAR(20),
	FCity VARCHAR(20), 
	FAge INT,
	FSalary INT
) 


        Oracle: 
        CREATE TABLE T_Person (FName VARCHAR2(20),FCity VARCHAR2(20), FAge INT,FSalary INT) 

注:下面結果僅僅在MSSQLServer中演示:

T_Person 表保存了人員信息,FName 字段為人員姓名,FCity 字段為人員所在的城市名,

FAge  字段為人員年齡,FSalary 字段為人員工資。然后運行以下的SQL語句向 T_Person

表中插入一些演示數據: 

       

INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Tom','BeiJing',20,3000); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Tim','ChengDu',21,4000); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Jim','BeiJing',22,3500); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Lily','London',21,2000); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('John','NewYork',22,1000); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('YaoMing','BeiJing',20,3000); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Swing','London',22,2000); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Guo','NewYork',20,2800); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('YuQian','BeiJing',24,8000); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Ketty','London',25,8500); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Kitty','ChengDu',25,3000); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Merry','BeiJing',23,3500); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Smith','ChengDu',30,3000); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary)
VALUES('Bill','BeiJing',25,2000); 
INSERT INTO T_Person(FName,FCity,FAge,FSalary) 
VALUES('Jerry','NewYork',24,3300); 

查看表中的內容:

select * from T_Person

開窗函數簡單介紹 
 
合函數一樣,開窗函數也是對行集組進行聚合計算,可是它不像普通聚合函數那樣

每組僅僅返回一個值,開窗函數能夠為每組返回多個值,由於開窗函數所運行聚合計算的行

集組是窗體。在ISO SQL規定了這種函數為開窗函數,在 Oracle中則被稱為分析函數,

而在DB2中則被稱為OLAP函數。  

要計算全部人員的總數,我們能夠運行以下的 SQL語句: 
SELECT COUNT(*) FROM T_Person 
 
       除了這樣的較簡單的使用方式, 有時須要從不在聚合函數中的行中訪問這些聚合計

算的值。比方我們想查詢每一個工資小於 5000元的員工信息(城市以及年齡) ,而且在

每行中都顯示全部工資小於5000元的員工個數,嘗試編寫以下的 SQL語句: 
SELECT FCITY , FAGE , COUNT(*)  
FROM T_Person 
HERE FSALARY<5000 
  運行上面的SQL以后我們會得到以下的錯誤信息: 
選擇列表中的列  'T_Person.FCity' 無效,由於該列沒有包括在聚合函數或 

 GROUP BY 子句中。 
  這是由於全部不包括在聚合函數中的列必須聲明在GROUP BY 子句中,

能夠進行例如以下改動: 
SELECT FCITY, FAGE, COUNT(*)  
FROM T_Person 
WHERE FSALARY<5000 
GROUP BY FCITY , FAGE 
  運行完成我們就能在輸出結果中看到以下的運行結果: 
               

   

  這個運行結果與我們想像的是全然不同的,這是由於GROUP  BY子句對結果集

進行了分組,所以聚合函數進行計算的對象不再是全部的結果集,而是每個分組。

 能夠通過子查詢來解決問題,SQL例如以下: 
SELECT FCITY , FAGE ,  

  SELECT COUNT(* ) FROM T_Person 
  WHERE FSALARY<5000 

FROM T_Person 
WHERE FSALARY<5000 
  運行完成我們就能在輸出結果中看到以下的運行結果:


  盡管使用子查詢可以解決問題,可是子查詢的使用很麻煩,使用開窗函數

則能夠大大簡化實現,以下的SQL語句展示了假設使用開窗函數來實現相同的效果: 

SELECT FCITY , FAGE , COUNT(*) OVER() 
FROM T_Person 
WHERE FSALARY<5000 
  運行完成我們就能在輸出結果中看到以下的運行結果: 

能夠看到與聚合函數不同的是,開窗函數在聚合函數后添加了一個OVER keyword。 
開窗函數的調用格式為: 
函數名(列) OVER(選項) 
    OVER   keyword表示把函數當成開窗函數而不是聚合函數。SQL  標准同意將全部聚 
合函數用做開窗函數,使用OVER keyword來區分這兩種使用方法。 
    在上邊的樣例中,開窗函數COUNT(*) OVER()對於查詢結果的每一行都返回全部 
符合條件的行的條數。OVERkeyword后的括號里還常常加入選項用以改變進行聚合運算的窗 
口范圍。假設OVERkeyword后的括號里的選項為空,則開窗函數會對結果集中的全部行進行 
聚合運算。  
  

總結:上述講述的是開窗函數的基本使用方法,希望對大家有所幫助!


免責聲明!

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



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