分析函數基於分組,計算分組內數據的聚合值,經常會和窗口函數OVER()一起使用,使用分析函數可以很方便地計算同比和環比,獲得中位數,獲得分組的最大值和最小值。分析函數和聚合函數不同,不需要GROUP BY子句,對SELECT子句的結果集,通過OVER()子句分組。
使用以下腳本插入示例數據:

;with cte_data as ( select 'Document Control' as Department,'Arifin' as LastName,17.78 as Rate union all select 'Document Control','Norred',16.82 union all select 'Document Control','Kharatishvili',16.82 union all select 'Document Control','Chai',10.25 union all select 'Document Control','Berge',10.25 union all select 'Information Services','Trenary',50.48 union all select 'Information Services','Conroy',39.66 union all select 'Information Services','Ajenstat',38.46 union all select 'Information Services','Wilson',38.46 union all select 'Information Services','Sharma',32.45 union all select 'Information Services','Connelly',32.45 union all select 'Information Services','Berg',27.40 union all select 'Information Services','Meyyappan',27.40 union all select 'Information Services','Bacon',27.40 union all select 'Information Services','Bueno ',27.40 ) select Department ,LastName ,Rate into #data from cte_data go
一,分析函數
分析函數通常和OVER()函數搭配使用,SQL Server中共有4類分析函數。
在OVER()函數中通常會對窗口內的數據進行排序,把有序數據從上向下看作是一個序列,對當前行而言,在序列上方的為后,在序列下方的為前。對當前組而言,第一行在組內的最上面,末尾行在組內的最下面。
注意:distinct子句的執行順序是在分析函數之后。
1,CUME_DIST 和PERCENT_RANK
CUME_DIST 計算的邏輯是:小於等於當前值的行數/分組內總行數
PERCENT_RANK 計算的邏輯是:(分組內當前行的RANK值-1)/ (分組內總行數-1),排名值是RANK()函數排序的結果值。
以下代碼,用於計算累積分布和排名百分比:
select Department ,LastName ,Rate ,cume_dist() over(partition by Department order by Rate) as CumeDist ,percent_rank() over(partition by Department order by Rate) as PtcRank ,rank() over(partition by Department order by Rate asc) as rank_number ,count(0) over(partition by Department) as count_in_group from #data order by DepartMent ,Rate desc
2,PERCENTILE_CONT和PERCENTILE_DISC
PERCENTILE_CONT和PERCENTILE_DISC都是為了計算百分位的數值,比如計算在某個百分位時某個欄位的數值是多少。
PERCENTILE_CONT ( numeric_literal ) WITHIN GROUP ( ORDER BY order_by_expression [ ASC | DESC ] ) OVER ( [ <partition_by_clause> ] ) PERCENTILE_DISC ( numeric_literal ) WITHIN GROUP ( ORDER BY order_by_expression [ ASC | DESC ] ) OVER ( [ <partition_by_clause> ] )
這兩個函數的區別是前者是連續型,后者是離散型。CONT代表continuous,連續值,DISC代表discrete,離散值。PERCENTILE_CONT是連續型,意味它考慮的是區間,所以值是絕對的中間值;而PERCENTILE_DISC是離散型,所以它更多考慮向上或者向下取舍,而不會考慮區間。
以下腳本用於獲得分位數:
select Department ,LastName ,Rate ,PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY Rate) OVER (PARTITION BY Department) AS MedianCont ,PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY Rate) OVER (PARTITION BY Department) AS MedianDisc ,row_number() over(partition by Department order by Rate) as rn from #data order by DepartMent ,Rate asc
3,LAG和LEAD
在一次查詢中,對數據表進行排序,把已排序的數據從上向下看作是一個序列,對當前行而言,在序列上方的為后,在序列下方的為前。
在同一分組內,對於當前行,Lag()函數用於獲取從當前行開始向后(或向上)計數的第N行,Lead()函數用於獲取從當前行開始向前(或向下)計數的第N行。
LAG (scalar_expression [,offset] [,default]) OVER ( [ partition_by_clause ] order_by_clause ) LEAD ( scalar_expression [ ,offset ] , [ default ] ) OVER ( [ partition_by_clause ] order_by_clause )
參數注釋:
- sclar_expression:標量表達式
- offset:默認值是1,必須是正整數,對於LAG()函數表示從當前行(current row)回退的行數,對於LEAD()表示從當前行向前進的行數。
- default :當offset超出分區范圍時要返回的值。 如果未指定默認值,則返回NULL。 default可以是列,子查詢或其他表達式,但必須跟sclar_expression類型兼容。
結果日期,這兩個函數特別適合用於計算同比和環比。
select DepartMent ,LastName ,Rate ,lag(Rate,1,0) over(partition by Department order by LastName) as LastRate ,lead(Rate,1,0) over(partition by Department order by LastName) as NextRate from #data order by Department ,LastName
按照DepartMent進行分組,對Document Control這一小組進行分析:
- 第一行,對於LastRate字段,向后不存在數據行,返回參數Default的值,字段NextRate的值是第二行的Rate字段的值。
- 第二行,LastRate是第一行的Rate字段的值,NextRate是第三行的Rate字段的值。對於中間行,依次類推。
- 最后一行,LastRate是倒數第二行的Rate字段的值,對於NextRate字段,由於最后一行向前不存在數據行,返回參數Default的值。
4,FIRST_VALUE和LAST_VALUE
獲取分組內排在最末尾的行和排在第一位的行:
LAST_VALUE ( [scalar_expression ) OVER ( [ partition_by_clause ] order_by_clause rows_range_clause )
FIRST_VALUE ( [scalar_expression ] ) OVER ( [ partition_by_clause ] order_by_clause [ rows_range_clause ] )
二,排名函數
SQL Server的排名函數是對查詢的結果進行排名和分組,TSQL共有4個排名函數,分別是:RANK、NTILE、DENSE_RANK和ROW_NUMBER,和OVER()函數搭配使用,按照特定的順序排名。
1,ROW_NUMBER函數
ROW_NUMBER函數實際上是一個序列,每個分組內都會創建一個序列,序列從1開始,按照順序依次 +1 遞增。
ROW_NUMBER ( )
OVER ( [ PARTITION_BY_clause ] order_by_clause )
分組內序列的最大值就是該分組內的行的數目。
2,RANK函數
RANK函數用於排名時,不會返回連續的整數。RANK函數的語法是:在分組內,按照特定的順序排名,序號從1依次遞增,排名函數以tie為單位,每個tie中的所有行的排名是相同的,排名可能是不連續的。
RANK ( ) OVER ( [ partition_by_clause ] order_by_clause )
排名的算法是:
- step1:按照指定的分區字段分組,在每個分組內按照指定的字段排序。
- step2:在每個分組內,如果相鄰的兩行或多行相同在排序字段上的值相同,那么這些行稱作一個tie,每個tie中的所有行都會獲得相同的排名。
- step3:后面的排名會計算每個tie中的行數,RANK函數不總是返回連續的整數,例如,班級中,A,B分數都是100分,C的分數是90分,那么A和B的排名是1,C的排名是3。
3,DENSE_RANK
DENSE_RANK函數用於排名時,會返回連續的整數。每個tie占用一個排名,每個tie中的所有行的排名是相同的。排名值是連續的
DENSE_RANK ( ) OVER ( [ <partition_by_clause> ] < order_by_clause > )
排名的算法是:
- step1:按照指定的分區字段分組,在每個分組內按照指定的字段排序。
- step2:在每個分組內,如果相鄰的兩行或多行相同在排序字段上的值相同,那么這些行稱作一個tie,每個tie中的所有行都會獲得相同的排名。
- step3:后面的排名會計算每個tie中的行數,RANK函數總是返回連續的整數,例如,班級中,A,B分數都是100分,C的分數是90分,那么A和B的排名是1,C的排名是2。
4,NTILE
在每個分組中,NTILE按照指定的順序,把數據行分為N個小組(tile),NTILE返回小組編號。在每個分組內,具有相同的小組編號的數據行,位於同一個小組。注意:小組的編號是按照行數,而不是按照列值。在同一分組內,存在兩行的列值相同,而小組編號不同。
NTILE (integer_expression) OVER ( [ <partition_by_clause> ] < order_by_clause > )
如果分區中的行數不能被integer_expression整除,那么會導致小組相差一個成員:較大的小組按OVER子句指定的順序位於較小的小組之前。 例如,如果把8行分為3個小組,前2個小組有3行,后一個小組有2行。
如果分區中的中行數能被integer_expression整除,那么每個小組具有相同的行數。
特別地,NTILE(4) 把一個分組分成4份,叫做Quartile。例如,以下腳本顯示各個排名函數的執行結果:
select Department ,LastName ,Rate ,row_number() over(order by Rate) as [row number] ,rank() over(order by rate) as rate_rank ,dense_rank() over(order by rate) as rate_dense_rank ,ntile(4) over(order by rate) as quartile_by_rate from #data
參考文檔: