SQL:分析函数、排名函数、聚合函数配合窗口函数 OVER 的用法

参考 1:Microsoft 中的 SQL Server 文档(分析函数、排名行数、聚合函数、OVER窗口函数)

参考 2:SQL Server 分析函数和排名函数      博主:悦光阴

分析函数基于分组,计算分组内数据的聚合值,经常会和窗口函数OVER()一起使用,使用分析函数可以很方便地计算同比和环比,获得中位数,获得分组的最大值和最小值。
分析函数和聚合函数不同,不需要GROUP BY子句,对SELECT子句的结果集,通过OVER()子句分组;

一,分析函数

分析函数通常和 OVER() 函数搭配使用,SQL Server 中共有4类分析函数。
注意:distinct 子句的执行顺序是在分析函数之后。 

1,分布函数:CUME_DIST、PERCENT_RANK

功能:计算某个值在某个值组内的累积分布换言之,CUME_DIST 计算某指定值在一组值中的相对位置。 

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

功能:

都是为了计算百分位的数值,比如计算在某个百分位时某个栏位的数值是多少;
如,20% —— 一组数据中,分布位置在 20% 处的数值、50% —— 分布位置在 50% 处的数值,也就是中位数;

语法:

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 行数据(即 offset=n),旧列中的第一行数据,在新列中为第 n+1 行数据;
LEAD:向上偏移 —— 如果偏移 n 行数据(即 offset=n),旧列中的第一行数据,在新列中为第 n+1 行数据,

语法:

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

偏移量;

如,offset=n,表示偏移了 n 行数据;
默认值是1,必须是正整数;

default

偏移后的偏移区的取值;

如, LAG 偏移了 n 行,则新列中的前 n 行的数据即为 default;

如果未指定默认值,则返回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

理解:

scalar_expression = Rate:对 Rate 列的数据进行偏移;
offset=1:偏移量设置为 1;(即偏移一行数据)
default=0:偏移区的数据设置为 0;

如新列 LastRate 的第一个分组的第 1 行数据;(向下偏移 1 行数据)
如新列 NextRate 的第一个分组的第 5 行数据;(向上偏移 1 行数据)

4,偏移函数:FIRST_VALUE、LAST_VALUE、NTH_VALUE

功能:

FIRST_VALUE:返回 scalar_expression 列中,分组中的第一行的数据;
LAST_VALUE:返回 scalar_expression 列中,分组中的最后一行的数据;
NTH_VALUE:返回 scalar_expression 列中,每个分组的偏移量;(即 offset 值)

语法:

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 ] )

scalar_expression —— 目标列:如果对该列进行了分组和排序,则返回该列中的每个分组中的第一行 / 最后一行的数据;

示例:

USE AdventureWorks2012;  
GO  
SELECT Name, ListPrice,   
       FIRST_VALUE(Name) OVER (ORDER BY ListPrice ASC) AS LeastExpensive   
FROM Production.Product  
WHERE ProductSubcategoryID = 37; 

理解:返回结果集中 Name 列中的第一行数据;

二,排名函数

TSQL共有4个排名函数:RANK、NTILE、DENSE_RANK、ROW_NUMBER,和 OVER() 函数搭配使用,按照特定的顺序排名。

1,ROW_NUMBER

这个函数赋予唯一的连续位次;

如,有 3 条排在第1位时,排序为:1,2,3,4······

ROW_NUMBER ( ) OVER ( [ PARTITION_BY_clause ] order_by_clause )

分组内序列的最大值就是该分组内的行的数目;

2,RANK

功能:在计算排序时,若存在相同位次,会跳过之后的位次;

如,有3条排在第1位时,排序为:1,1,1,4······

RANK ( ) OVER ( [ partition_by_clause ] order_by_clause )

3,DENSE_RANK

功能: 在计算排序时,若存在相同位次,不会跳过之后的位次。

如,有3条排在第1位时,排序为:1,1,1,2······

DENSE_RANK ( ) OVER ( [ <partition_by_clause> ] < order_by_clause > )

4,NTILE

功能:对每个分组的所有数据进行分块标记,每个标记就是该行数据所在第几个数据块;

如,integer_expression=3:把一个分组的数据分成 3 分;(则每个数据块的行数 = 分组数据总行数 / 3,如果不能整除,最后一个数据块的数据记录最少)

语法:

NTILE (integer_expression) OVER ( [ <partition_by_clause> ] < order_by_clause > )

 

示例

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   test_data

三、聚合函数 配合 OVER 函数

一般配合 OVER 函数使用的聚合函数:SUM、COUNT、AVG、MAX、MIN

功能:

SUM、AVG:返回累积计算结果;

如,第 n 行的数据,是从前 n 行数据中计算得到;

COUNT、MAX、MIN:返回分组中的行数、最大值、最小值,一个分组返回一行数;

语法:

对一列的分组进行计算

<窗口函数> OVER([pattition by col_a] ORDER BY col_b)

不分组,直接对某列进行计算

<窗口函数(col_a)> OVER(ORDER BY col_b)

示例:

SUM:累积求和

第 n 行数据为前 n 行数据的总和

select product_id, product_name, sale_price,
       sum(sale_price) over (order by product_id) as current_sum
from Product;

AVG:累积求平均

第 n 行的数据为前 n 行数据的平均数

select product_id, product_name, sale_price,
       avg(sale_price) over (order by product_id) as current_sum
from Product;

AVG:移动平均(一)

计算前 n 行 + 改行数据的平均值;

如,n=2:计算相邻 3 行数据,即 (前 2 行 + 本身行数据) / 3;

如,当 n=2 时,第 10 行的数据 = (第8行 + 第9行 + 第10行) / 3

语法:

<聚合函数> OVER([PARTITION BY col_a] ORDER BY col_b ROWS n PRECEDING)

示例:

SELECT product_id, product_name, sale_price,
       AVG (sale_price) OVER (ORDER BY product_id ROWS 2 PRECEDING) AS moving_avg
FROM Product;

n = 2:计算前两行+本行数据的平均值;

第 3 行:1833 = (1000+500+4000) / 3
第 4 行:2500 = (500+4000+3000) / 3
第 5 行:4600 = (4000+3000+6800) / 3

AVG:移动平均(二)

功能:(计算上一行 + 下一行 + 该行) / 3

语法及示例:

SELECT product_id, product_name, sale_price,
       AVG(sale_price) OVER (ORDER BY product_id
                              ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS moving_avg
--使用between规划范围,语句意思为rows 1 preceding 到 rows 1 following FROM Product;

4600 = (4000+3000+6800) / 3

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注