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

2021-06-06 03:54:20 字數 4345 閱讀 4945

在開窗函式出現之前存在著很多用 sql 語句很難解決的問題,很多都要通過複雜的相關子查詢或者儲存過程來完成。為了解決這些問題,在2023年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);

檢視表中的內容:

開窗函式簡介 

與 聚合函式一樣,開窗函式也是對行集組進行聚合計算,但是它不像普通聚合函式那樣

每組只返回乙個值,開窗函式可以為每組返回多個值,因為開窗函式所執行聚合計算的行

集組是視窗。在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 關鍵字。 

開窗函式的呼叫格式為: 

函式名(列) over(選項) 

over   關鍵字表示把函式當成開窗函式而不是聚合函式。sql  標準允許將所有聚 

合函式用做開窗函式,使用over 關鍵字來區分這兩種用法。 

在上邊的例子中,開窗函式count(*) over()對於查詢結果的每一行都返回所有 

符合條件的行的條數。over關鍵字後的括號中還經常新增選項用以改變進行聚合運算的窗 

口範圍。如果over關鍵字後的括號中的選項為空,則開窗函式會對結果集中的所有行進行 

聚合運算。    

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

在開窗函式出現之前存在著非常多用 sql 語句非常難解決的問題,非常多都要通過複雜的相關子查詢或者儲存過程來完畢。為了解決這些問題,在2003年iso sql標準增加了開窗函式,開窗函式的使用使得這些經典的難題能夠被輕鬆的解決。眼下在 mssqlserver oracle db2 等主流資料庫中都提...

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

在開窗函式出現之前存在著非常多用 sql 語句非常難解決的問題,非常多都要通過複雜的相關子查詢或者儲存過程來完畢。為了解決這些問題,在2003年iso sql標準添 了開窗函式,開窗函式的使用使得這些經典的難題能夠被輕鬆的解決。眼下在 mssqlserver oracle db2 等主流資料庫中都提...

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

在開窗函式出現之前存在著非常多用 sql 語句非常難解決的問題,非常多都要通過複雜的相關子查詢或者儲存過程來完畢。為了解決這些問題,在2003年iso sql標準增加了開窗函式,開窗函式的使用使得這些經典的難題能夠被輕鬆的解決。眼下在 mssqlserver oracle db2 等主流資料庫中都提...