在開窗函數出現之前存在着非常多用 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后的括號里的選項為空,則開窗函數會對結果集中的全部行進行
聚合運算。
總結:上述講述的是開窗函數的基本使用方法,希望對大家有所幫助!