SQL ——視窗函式簡介
目錄
1、視窗函式的描述
視窗函式作用於一個數據行集合。視窗是標準的SQL術語,用來描述SQL語句內OVER子句劃定的內容,這個內容就是視窗函式的作用域。而在OVER子句中,定義了視窗所覆蓋的與當前行相關的資料行集、行的排序及其他的相關元素。
標準SQL對視窗函式的第一次支援是在SQL:1999的擴充套件文件中,當時,它們稱為“OLAP”函式。從那以後,每次標準版本的修訂都會增強對視窗函式的支援,直到現在的SQL:2003、SQL:2008、SQL:2011。最新的SQL標準版本,已經有了非常豐富和全面的視窗函式,顯示出標準委員會對這一概念的堅定,以及從更多視窗函式和更多功能兩個方面持續增強支援標準。
2、視窗函式中的元素
視窗函式的行為描述出現在函式的OVER子句中,並涉及多個元素。3個核心元素分別是分割槽、排序和框架。不是所有的視窗函式都支援這3個元素。
2.1、分割槽
分割槽元素是由PARTITION BY子句定義,並被所有的視窗函式支援。他對當前計算的視窗函式進行限制,僅僅那些在結果集的分割槽列中與當前行有相同值的行才能進入視窗。如果沒有指定PARTITION BY子句,視窗就沒有限制。換種說法就是:如果沒有顯示指定分割槽,則預設分割槽就是把整個查詢結果集當作一個分割槽。有一點不太明顯,這裡提出來:同一個查詢中的不同函式,可能會有不同的分割槽描述。
2.2、排序
排序元素定義計算的順序,如果與分割槽有關,則是在分割槽內的順序。在標準的SQL中,所有函式都支援排序元素。起初SQL SERVER不支援聚合函式中的排序元素,而僅僅支援分割槽。對聚合函式紅排序的支援,是從SQL SERVER 2012 開始的。
有趣的是,針對不同的函式類別,排序元素有輕微的不同意義。對於排名函式,排序是直觀的。而聚合視窗函式的排序和排名視窗的排序略有意義上的不同。在聚合中,與某些人認為的相反,排序與聚合的順序無關;然而,排序元素為下面將描述的框架選項賦予一定的含義,換句話說,排序元素幫助限定在視窗內的行。
2.3、框架
從本質上來說,框架是一個在分割槽內對行進行進一步限制的篩選器。它適用於聚合視窗函式,也適用於三個偏移函式:FIRST_VALUE、LAST_VALUE、NTH_VALUE。把這個視窗元素想成是基於給定的排序,在當前行所在分割槽中定義兩個點,這兩個點形成的框架之間的行才會參與計算。
在標準的框架描述中,包含一個ROWS或RANGE選項,用來定義框架的開始行和結束行,這兩行也可以形成“框架外”(框架內的行被排除在計算外)視窗選項。SQL SERVER 2012 開始支援框架,完全實現ROWS選項,部分實現RANGE選項,尚未實現“框架外”視窗選項。
ROWS選項允許我們用相對當前行的偏移行數來指定框架的起點和終點。RANGE選項更具靈活性,可以以框架起終點的值於當前行的值的差異來定義偏移行數。“框架外”視窗選項用來定義如何對當前行及具有相同值的行進行處置。
3、支援視窗函式的查詢元素
並不是所有的查詢子句都支援視窗函式,相反,僅僅SELECT和ORDER BY 子句支援視窗函式。為幫助理解,我們先看看SQL不同子句的執行順序:
1、FROM
2、WHERE
3、GROUP BY
4、HAVING
5、SELECT
5.1、Evalute Expressions(判斷表示式)
5.2、刪除重複資料
6、ORDER BY
7、OFFSET-FETCH/TOP
只有SELECT和ORDER BY 子句直接支援視窗函式。做這個限制的原因是為了避免二義性,因此把(幾乎是)查詢的最終結果當作視窗的起點。如果視窗函式可以早於SELECT階段出現,那麼通過一些查詢表單會無法得到正確的結果。
4、視窗函式類別
視窗函式分為排名函式、分佈函式、偏移函式等。
4.1、排名函式
SQL標準支援4種用於排名計算的視窗函式。它們是:ROW_NUMBER、NTILE、RANK和DENSE_RANK。在標準中,前兩者是一類,後兩者是另一類。
ROW_NUMBER函式根據指定的順序,從1開始計算連續的行號。
NTILE函式把視窗分割槽裡的資料行分成數量大致相等的塊(根據輸入的塊數和指定的視窗排序)。
注意:為避免有人認為分塊和分頁相似,這裡提醒大家,不要把二者混淆起來。在分頁中,頁的大小是常量,並且頁碼是動態的——查詢結果集除以頁面大小後得到的數值。而分開中,塊的數量是常量,塊的大小是動態的——行的數量除以設定的塊的數量後得到的數值。分頁在何處使用是很明顯的,分塊通常用於分析目的——那些需要涉及基於某種衡量順序,把資料分到預先設定的固定數量、相同大小的桶(bucket)中。
RANK(排名)和DENSE_RANK(密集排名)函式的計算和ROW_NUMBER函式類似,唯一不同的是,它們在視窗分割槽內生成的值不必是唯一的。當視窗排序方向是升序時,RANK函式計算分割槽內排序值比當前行小的行的數量,在次數量上加1,就是當前行的排名;DENSE_RANK函式計算分割槽內相異的(distinct)排序值比當前行小的行的數量,在此數量上加1,就是當前行的排名。當視窗排序方向是降序時,RANK函式計算分割槽內排序屬性比當前行大的行的數量,在此數量上加1,就是當前行的排名;DENSE_RANK函式計算分割槽內相異的(distinct)排序值比當前行大的行的數量,在此數量上加1,就是當前行的排名。
4.2、分佈函式
視窗分佈函式主要為靜態統計服務提供資料的分佈情況。SQL Server 2012引入了兩種視窗分佈函式的支援:排名分佈函式和逆分佈函式。排名分佈函式有兩種:PERCENT_RANK(百分位排名)和CUME_DIST(累積分佈),逆分佈函式也有兩個:PERCENT_CONT(百分位連續)和PERCENTILE_DISC(百分位離散)。
根據標準SQL,分佈函式計算資料行在視窗分割槽中的相對排名,把它表達成介於0~1之間的比值——我們大多數人把它看做百分比。
假設rk 為資料行的RANK值,RANK函式的視窗描述與分佈函式的視窗描述相同。假設nr為視窗分割槽內資料行的行數。假設np為領先或與當前行的排序值相同的行的數目(為比當前rk減1大的最小rk值,如果當前的rk為最大值,np則等於nr)。
PERCENT_RANK(百分位排名)計算公式如下:(rk-1)/(nr-1),PERCENT_RANK(百分位排名)的計算公式如下:np/nr。
逆分佈函式,通常叫百分位,我們可以把它執行的計算當作是排名分佈函式的倒數。
PERCENTILE_DISC(百分位離散)函式(DISC為離散分佈模型)返回組中第一個符合條件的值,條件是:其累計分佈(CUME_DIST函式)大於等於輸入值。
PERCENT_CONT(百分位連續)函式(CONT為連續分佈函式)比較難理解(PERCENT_CONT(@pct) WITHIN GROUP(ORDER BY 分數))。舉個簡單示例,想象對一行數為偶數的組進行中值計算。我們需要內插值來支援連續分佈假定,插入的值落在兩個中間點的中間,意味著它是兩個中間點的平均值。
4.3、偏移函式
視窗偏移函式包括兩種型別的函式。一種是偏移量是相對於當前行的,這個類別的包括LAG和LEAD函式;另一個類別函式的偏移量是相對於視窗框架的開始和結尾的,這個類別包括FIRST_VALUE、LAST_VALUE和NTH_VALUE。第一類別中的函式(LAG和LEAD)支援視窗分割槽子句以及視窗排序子句。當然,後者的存在賦予偏移量以邏輯意義。第二類別中的函式(FIRST_VALUE、LAST_VALUE和NTH_VALUE)在支援視窗分割槽子句和排序子句的基礎上,還支援視窗框架子句。
LAG和LEAD函式允許我們從視窗分割槽中,根據給定的相對於當前行的前偏移量(LAG)和後偏移量(LEAD),返回對應行的值。如果沒有指定,偏移量預設為1。
FIRST_VALUE和FIRST_VALUE分別返回框架的第一行和最後一行所有查詢的值。NTH_VALUE函式作用是中的相對視窗框架第一行或最後一行的偏移量,使得我們可以取得對應這個偏移量的記錄值。
PS:1、最近看了關於SQL視窗函式也可作為T-SQL效能優化方案的相關書籍,於是整理了下相關概念。
2、此篇提到的知識針對SQL SERVER 2012中有的視窗函式。
3、此篇主要是為了整理視窗函式在T-SQL中的應用案例而做的準備工作。