窗口函數(開窗函數)及OVER子句(2):窗口與分組的區別

窗口函數(開窗函數)及OVER子句(2):窗口與分組的區別

若覺得本文寫得還可以,請多多關注本人所作書籍《C++語法詳解》電子工業出版社出版,作者 黃勇,網盤地址:
https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

本文爲原創文章,轉載請註明出處,或註明轉載自“黃邦勇帥(原名:黃勇)

三、窗口函數的特點及與分組、子查詢的區別
1、窗口函數和聚合函數都是作用於行集的,因此,使用窗口聚合函數能實現的方案,通常可以使用分組查詢或子查詢替代,但是窗口聚合函數通常優於替代方案,下面對其進行講解。
2、不同的窗口函數可以使用不同的窗口進行計算,而分組查詢的分組是在查詢中定義的,所有計算都使用相同的集合進行。比如,

select a,sum( c), avg ( c) from T4 group by a; 

以上分組語句中sum 和avg的計算都是在由列a產生的分組上進行計算的

select a,sum( c) over (partition by a),avg( c) over(partition by b) from T4

以上語句中的窗口聚合函數sum是在由列a定義的窗口上進行計算的,而avg是在由列b定義的窗口上進行計算的。
3、窗口函數不會丟失詳細信息
窗口函數是根據窗口進行計算的,並且會爲查詢結果集的每一行返回一個標量結果值,分組查詢一個組只返回一個值,因此分組查詢會失去細節信息,而窗口函數則不會。比如
select a, sum( c) from T group by a
以上語句對c列求和,由於是僅使用了列a進行分組,因此無法查看到c列各行值的詳細信息,若使用窗口函數,則可以查看到c列及其他列各行值的詳細信息,比如

select a,c,sum( c) over(partition by a) from T4

當實際應用中需要計算聚合信息和詳細信息時,窗口函數比分組查詢能更好,詳見後文。
4、對使用了相同窗口的窗口函數,只會對窗口內的數據訪問一次,即只會對源表進行一次掃描,從而提高性能。從此優點可見,窗口函數的性能明顯高於使用子查詢替代窗口函數的方案,詳見後文的示例
5、窗口是在對錶進行了表操作符(如聯接)、篩選(比如WHERE子句)、分組之後的結果集基礎之上定義的,這樣就不用重複設定對外部查詢的限定,而子查詢是從頭開始的查詢,需要重複設定對外部查詢的限定,因此窗口函數的代碼會明顯短於使用子查詢替代窗口函數的方案,並且可提高性能,比如

select a, sum(c) over (partition by a)from T4 where a=5	--窗口函數
select a,
(select sum(c)from T4 	--使用子查詢替代窗口函數
where a=5   			--外部查詢的WHERE子句需要重新限定,增加了代碼長度
group by a ) from T4 where a=5 

6、若需要對窗口函數的計算結果進行篩選,則可使用公用表表達式CTE來解決,比如

WITH S AS(select a, sum(c) over(partition by a) AS x from T4)
select * from S where x=3

7、注意SELECT語句的同時性概念,比如SELECT a as x, x+b FROM T4;是錯誤的,因爲a as x與x+b是同時執行的,因此,在執行x+b時,列a的別名x還未創建成功。同時性概念意味着,在同一時刻,所有的窗口是同時存在的。
示例:表T4具有(dat,val)兩列,其中dat表示日期,val表示當月的銷量,試計算當月銷量佔年總銷量的百分比,當月銷量佔年平均銷量的百分比
解:當月銷量爲詳細信息,年總銷量和年平均銷量是聚合信息,若使用分組查詢進行處理,將比較複雜,若使用窗口函數,則比較容易實現。下面爲3種實現方法
方法1:使用分組查詢

WITH TT as 								--使用公用表表達式(CTE)存儲聚合信息
(	select year(dat)AS y, 
sum(val)AS yval,avg(val)as v 		--計算年總銷量和年平均銷量
from T7 group by year(dat))
select dat,val,							--顯示詳細信息
			100.0*val/yval,100.0*val/v 			--需要求解的數據
from T7 join TT on year(T7.dat)=TT.y		--還需要把CTE與表T7進行聯接

方法2:使用窗口函數

select dat,val										--顯示的詳細信息
		,100.0*val/sum(val) over(partition by year(dat))		--當前月銷量與年總銷量之比
	 , 100.0*val/avg(val) over(partition by year(dat)) 	--當前月銷量與年平均銷量之比
from T7;

方法3:使用子查詢

select dat,val
		 ,100.0*val/(select sum(val) from T7 group by year(dat))
		,100.0*val/(select avg(val) from T7 group by year(dat)) 

由以上示例可見
1)、分組查詢需要引入CTE和聯接,當需要計算的量越來越多時,就需要更多的CTE和聯接,因此分組查詢會變得越來越複雜。由此可見,窗口函數可很好的解決這個問題。
2)、子查詢有以下問題,第一,代碼太長,第二,對於每個子查詢,都需要單獨掃描一次源表,因此,子查詢越多,掃描源表的次數就越多,從而性能就越低,另外,子查詢還需要對外部查詢的限定(比如WHERE子句)進行重複限定。從以上對窗口函數的講解可知,窗口函數可很好的解決子查詢的這些問題

作者:黃邦勇帥(原名:黃勇)

在這裏插入圖片描述

主要參考文獻:
1、C++語法詳解 黃勇 編著 電子工業出版社 2017年7月
2、SQL Server 2012 T-SQL基礎教程 [美] Itzik Ben-Gan著 張洪舉 李聯國 張昊天 譯 人民郵電出版社 2013年12月
3、T-SQL性能調優祕笈------基於SQL Server 2012窗口函數 [美] Itzik Ben-Gan著 林德玲 方鑫譯 人民郵電出版社 2014年8月
4、SQL Server 2005技術內幕:T-SQL查詢 [美] Itzik Ben-Gan , Lubor Kollar , Dejan Sarka著 趙立東 唐燦 劉波 譯 趙立東 審校 電子工業出版社 出版日期不詳
4、SQL Server 2005技術內幕:T-SQL程序設計 [美] Itzik Ben-Gan , Dejan Sarka , Roger Wolter著 趙立東 譯 電子工業出版社 出版日期不詳
5、Microsoft SQL Server 2008技術內幕:T-SQL語言基礎 [美] Itzik Ben-Gan著 成保棟 張昱 譯 電子工業出版社 2009年10月
6、Microsoft SQL Server 2008技術內幕:T-SQL查詢 [美] Itzik Ben-Gan , Lubor Kollar , Dejan Sarka , Steve Kass著 成保棟 李保強 譯 電子工業出版社 2010年9月

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章