窗口函数(开窗函数)及OVER子句(3):OVER子句完整语法及各选项详解

窗口函数(开窗函数)及OVER子句(3):OVER子句完整语法及各选项详解

若觉得本文写得还可以,请多多关注本人所作书籍《C++语法详解》电子工业出版社出版,作者 黄勇,网盘地址:
https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)

四、OVER子句完整语法
OVER子句完整语法如下:
在这里插入图片描述
为避免混淆,本小节会把分区子句称为PARTITION BY从属子句,排序子句称为ORDER BY从属子句

分区子句< PARTITION BY clause >
1、所有窗口函数都支持分区子句。
2、分区子句用于对查询结果集进行分区,其规则为:只有在结果集的分区列中与当前行的分区列有相同值的行才进入分区,其余行被过滤掉,若未指定PARTITION BY子句,则表示未分区,此时默认分区为整个查询结果集,若未指定框架子句,则由分区子句划分的分区就是最终定义的窗口。比如PARTITION BY a,若当前行列a的值为1,则只有查询结果集中所有列a的值为1的行才进入分区,其余行被过滤掉。该子句的示例在前文已讲解过,此处不再重述。

排序子句< ORDER BY clause >
1、所有窗口函数都支持排序子句,注意:SQL Server2012之后才开始在聚合窗口函数中支持ORDER BY从属子句。
2、ORDER BY从属子句用于定义在窗口内的顺序,不同类型的窗口函数,ORDER BY从属子句的意义会有一些不相同,具体规则详见对相应窗口函数的讲解,另外,排序子句还会帮助框架子句对窗口进行进一步的限定或过滤
3、窗口函数的排序规范与显示(或输出)时的排序规范不同,窗口函数的排序子句,只影响窗口内的数据,若指定了显示排序,则最后输出的排序以显示排序为准,而不是以窗口函数的排序为准,若需要按一定顺序显示,则需要指定显示排序。显示排序指的是SELECT语句中的ORDER BY子句,比如SELECT * FROM T ORDER BY a,其中的ORDER BY就是显示排序
4、窗口函数、NEXT VALUE FOR 函数不支持将整数索引作为 ORDER BY 子句表达式。但可以使用子查询返回一个常量作为排序子句的元素,比如ORDER BY (SELECT 3)就是正确的,同理ORDER BY (select a from T4 where a=1),若子查询返回的值是唯一的,也是正确的

框架子句< ROW or RANGE clause >
1、框架子句适用于聚合窗口函数和3个偏移函数(FIRSST_VALUE、LAST_VALUE、NTH_VALUE),注意:排名函数不支持框架子句。
2、框架子句是在一个分区内对行的进一步限制或过滤。也就是说,PARTITION BY从属子句是对窗口的第一次过滤,框架子句是在第一次过滤的基础上进行的第二次过滤,由框架子句过滤后的窗口,将成为最终的窗口。
3、框架子句过滤窗口的基本规则是:基于排序子句的顺序,在当前行所在分区中定义两个点,在这两点之间能形成框架的行才会进入窗口,其余行被再次过滤掉。
4、SQL Server使用ROWS或RANGE选项来定义框架的开始行和结束行,这两个选项的基本规则如下:
 ROWS选项使用相对于当前行的偏移行数来定义框架的起点和终点。
 RANGE选项可以使用框架起/终点的值与当前行的值的差异来定义偏移的行数,SQL Server2017只实现了该选项的部分功能。因此本文主要对ROWS选项进行讲解,在SQL Server中,RANGE与ROWS的原理是类似的,但是排序子句会对RANGE有影响,详见后文
 ROWS/RANGE选项各参数的意义,可参阅语法的注释,现在应该容易理解了
5、框架子句过滤分区的基本规则
1)、当使用< window frame preceding > 子句定义框架区域时,该子句中的参数只能用于指定窗口的起点,窗口的终点此时为CURRENT ROW(即当前行),比如ROWS 2 PRECEDING与ROWS BETWEEN 2 PRECEDING AND CURRENT ROW相同,表示窗口总共有3行,包括当前行的前2行和当前行,假设当前行为第5行且当前行所在分区足够大,则该行的窗口为第3,4,5行
2)、注意:不能只使用< window frame following > 子句定义框架区域,比如ROWS 2 FOLLOWING是错误的语句。
3)、当< 整数值> FOLLOWING 指定为窗口起点时,终点不能是< 整数值> PRECEDING 或CURRENT ROW,比如,ROWS BETWEEN 1 FOLLOWING AND CURRENT ROW,或ROWS BETWEEN 1 FOLLOWING AND 1 PRECEDING都是错误的,
4)、RANGE 不能用于 < 整数值> PRECEDING 或 < 整数值> FOLLOWING。也就是说,使用RANGE时不能使用数值指定行数
5)、下面列举几个示例
在这里插入图片描述
6、RANGE选项定义框架的原理
RANGE选项定义的窗口除按照ROWS规则确定的行外,还包含ORDER BY从属子句列表中列的值与当前行相应列具有相同值的所有行,这主要影响当使用CURRENT ROW确定窗口的起点或终点时。比如表有(a, b, c, d)四列,假设有(5, 2, 8, 9),(5, 6, 1, 2),(5, 6, 3, 4)三行,有语句

PARTITION BY a ORDER BY a, b RANGE UNBOUNDED PRECEDING

那么,行(5, 6, 1, 2)的窗口为(5, 2, 8, 9),(5, 6, 1, 2),(5, 6, 3, 4)三行。按照ROWS规则确定的行有(5, 2, 8, 9)、(5, 6, 1, 2),另外,还包含(a, b)列的值为(5, 6)的行(5, 6, 3, 4),若把RANGE修改为ROWS,则当前行(5, 6, 1, 2)的窗口只有(5, 2, 8, 9),(5, 6, 1, 2)两行。
7、ORDER BY从属子句对框架子句的影响
在这里插入图片描述

示例5.3:ROWS定义框架的原理(输出结果见图5.3)
select *,sum(c)over(partition by a order by a,b,c ROWS 2 PRECEDING ) as 框架1
		,sum(c)over(partition by a order by a,b,c ROWS UNBOUNDED PRECEDING) as 框架2
,sum(c)over(partition by a order by a,b,c
ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) as 框架3	
		from T4 order by a,b,c;	--与框架子句排序一致,以免输出时顺序不一致

在这里插入图片描述
在这里插入图片描述

示例5.4:RANGE定义框架的原理(输出结果见图5.4)
select *,sum(c)over(partition by a order by a,b ROWS CURRENT ROW ) as 框架1
		,sum(c)over(partition by a order by a,b RANGE CURRENT ROW) as 框架2
		,sum(c)over(partition by a order by a,b ROWS UNBOUNDED PRECEDING) as 框架3
		,sum(c)over(partition by a order by a,b RANGE UNBOUNDED PRECEDING) as 框架4
		,sum(c)over(partition by a order by a,b) as 框架5	--框架5与框架4相同
		,sum(c)over(order by a,b RANGE UNBOUNDED PRECEDING) as 框架6  --注意该框架
		from T4 order by a,b;

在这里插入图片描述
示例说明:
1、框架1的过滤条件为ROWS CURRENT ROW,因此窗口只有当前行一行,对窗口内c列进行求和,就是该行c列的值
2、框架2的过滤条件为RANGE CURRENT ROW,表示窗口包含ORDER BY从属子句列表中列的值与当前行相应列具有相同值的所有行,因此,行(5, 6, 11, 12)的窗口为(a, b)列的值为(5, 6)的所有行,即窗口为(5, 6, 11, 12)、(5, 6, 3, 1)、(5, 6, 5, 4),对该窗口内的c列进行求和,其结果为19(即11+3+5),从这里可以明显看到RANGE与ROWS的区别。行(5, 6, 3, 1)、(5, 6, 5, 4)的原理与行(5, 6, 11, 12)相同,其余行的窗口都仅为当前行一行。
3、框架3的过滤条件为ROWS UNBOUNDED ROW,其窗口为所在分区的开头直至当前行,具体从略,详见正文及上一示例的讲解
4、框架4的过滤条件为RANGE UNBOUNDED ROW,表示窗口除包含按照ROWS规则确定的行外,还包含ORDER BY从属子句列表中列的值与当前行相应列具有相同值的所有行,因此,行(5, 6, 11, 12)的窗口为,按照ROWS规则确定的行(5, 1, 2, 3)、(5, 6, 11, 12),还包含(a, b)列的值为(5, 6)的行(5, 6, 3, 1)、(5, 6, 5, 4),对窗口内的c列进行求和,其结果为21(即2+11+3+5)。行(5, 6, 3, 1)、(5, 6, 5, 4)的原理与行(5, 6, 11, 12)相同,(5, 9, 10, 11)、(5, 11, 22, 33)、(4, 10, 1, 8)的窗口为所在分区的开头直至当前行,除此之外的其余行的窗口都仅为当前行一行。
5、框架5与框架4是相同的,从略
6、框架6没有PARTITION BY子句,因此,框架6的当前行所在的分区将是整个查询结果集,RANGE UNBOUNDED ROW将在整个查询结果集的基础上进行过滤,比如,行(4, 10, 1, 8),因整个查询结果集为该行所在分区,所以,其窗口为该行所在分区的开头直至当前行,即窗口为(1, 2, 3, 4)、(2, 3, 4, 5)、(4, 1, 2, 3)、(4, 10, 1, 8),对窗口内的c列进行求和,其结果为10(即3+4+2+1);行(5, 6, 11, 12)的窗口共有8行,即(1, 2, 3, 4)到(5, 6, 5, 4)之间的所有行(含起点和终点),对窗口内的c列进行求和,其结果为31(即3+4+2+1+2+11+3+5)

作者:黄邦勇帅(原名:黄勇)

在这里插入图片描述

主要参考文献:
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月

猜你喜欢

转载自blog.csdn.net/hyongilfmmm/article/details/93889663