对于Select子句查询的结果集,可以按照指定的字段进行分区,如下图所示,按照Province字段来对查询的结果集进行分区,可以认为,每一个分区就是一个窗口,因此,窗口是数据行的集合,是Select查询结果集的一个子集。

在TSQL脚本的OVER()子句中,使用Partition By 子句进行分区。在同一分区中,可以按照一定的条件,把分区中的数据行再次细分,按照固定数量(rows)或值范围(range)来限制数据行,把这个数据行集称作一个窗口。

通常把分区和窗口不加区分,统称为窗口。在下文中,为了便于区分,我们把Partition By作用的结果记作分区,把rows 和 range作用的结果记作窗口,窗口中的数据行是分区的子集。

窗口函数是应用于窗口和分区的函数,共分为三类:排名函数,分析函数和聚合函数。注意OVER()子句执行的顺序:OVER()子句在SELECT子句和DISTINCT子句之后执行,在ORDER BY子句之前执行,DISTINCT子句是在SELECT子句之后执行。

下文使用的示例数据使用以下代码创建:

create table dbo.dt_test
(
ID int,
Code int
)
go --insert data
insert into dbo.dt_test(ID,Code)
values(3,1),(3,2),(1,1),(1,2),(2,3),(1,2)
go

一,基于分区的运算

窗口和分区都是通过OVER()子句来定义的,使用partition by 子句把结果集划分为多个分区,使用rows 或 range命令把分区分为多个窗口。

基于分区的运算主要是指:

  • 基于分区做聚合运算时:把每个分区作为一个GROUP BY的分组,基于分组做聚合运算。
  • 基于分区做排名运算时:分区中的行集按照OVER()子句的ORDER BY子句指定的顺序排名。
  • 基于分区做数据分析:主要是基于分区做百分位、相对位置百分比、排名百分比等运算。

当使用Over()函数计算整个分区的聚合值时,partition by子句是必需的,Order by 子句要省略:

select ID
,Code
,count(0) over(partition by Code) as Count_Over
,sum(ID) over(partition by Code) as Sum_Over
from dbo.dt_test

二,限制窗口的数据行

OVER()子句使用Rows和Range来限制分区中的数据行,用于对分区的数据行进行细分,得到分区的部分数据行。这两个两个关键字必须跟在Order By子句,都是基于当前行(Current Row)向前或向后来限制分区的数据行。

OVER ( [ <PARTITION BY clause> ]  [ <ORDER BY clause> ]  [ <ROW or RANGE clause> ] ) 

<ROW or RANGE clause> ::= { ROWS | RANGE } <window frame between>

<window frame between> ::= BETWEEN <window frame preceding> AND <window frame following>
<window frame preceding> ::= UNBOUNDED PRECEDING | unsigned_value PRECEDING | CURRENT ROW
<window frame following> ::= UNBOUNDED FOLLOWING | unsigned_value FOLLOWING | CURRENT ROW

Rows 和 Range子句中的特殊关键字:

  • UNBOUNDED PRECEDING:用于指定分区的第一行
  • UNBOUNDED FOLLOWING:用于指定分区的最后一行
  • CURRENT ROW:指定当前数据行
  • <unsigned_value> PRECEDING:在分区中,指定相对于当前行之前的数据行数量,unsigned_value是>0的整数
  • <unsigned_value> FOLLOWING:在分区中,指定相对于当前行之后的数据行数量,unsigned_value是>0的整数

在Over()子句中,使用Rows 或Range 命令进一步限制分区的数据行,在对分区进行细分时,必须注意:

1,必需条件

Rows 和 Range必须跟在Order by 子句之后,在同一个分区中对排序的结果集进行限制。经过我的观测,当在分区中使用order by子句后,SQL Server 默认的操作是:在order by子句之后追加 range between unbounded preceding and current row

range between unbounded preceding and current row

2,Rows 关键字

在同一个分区中,基于当前行(Current Row),通过指定一个固定数量的行数来限制分区中的数据行,

例子1,在同一个分区中,从分区的第一行到当前行:

rows between unbounded preceding and current row

例子2,同一分区中,从当前行到下一行:

rows between current row and 1 following

3,Range 关键字

在同一分区中,使用排序列的值的范围来限制分区中的数据行,当排序列存在重复值,重复的多行属于同一个范围。Range命令只能用于从分区的开始或者从结尾到当前行,不能使用 <unsigned_value> PRECEDING 和<unsigned_value>  FOLLOWING,Range命令的格式只能是:

range between unbounded preceding and current row
range between current row and unbounded following

4,Rows 和 Range的区别

在同一个分区中,对于下面的命令,如果排序列不存在重复值,那么Rows和Range返回的结果是相同的;如果排序行存储在重复值,那么Rows和Range返回的结果可能不同。

range|rows between unbounded preceding and current row
range|rows between current row and unbounded following

三,举例说明基于值范围(Range)的滑动窗口

窗口可以基于值范围进行滑动,从窗口的第一行开始,到当前行的值结束。在Over()子句中,Partition By定义分区,Order By定义窗口中滑动的方向。

举个例子,使用以下代码创建基于值范围的滑动窗口:

select ID
,Code
,count(0) over(partition by Code order by ID) as Count_Over
,sum(ID) over(partition by Code order by ID) as Sum_Over
,count(0) over(partition by Code order by ID range between unbounded preceding and current row) as Count_Over
,sum(ID) over(partition by Code order by ID range between unbounded preceding and current row) as Sum_Over
from dbo.dt_test
order by Code
  ,ID

查询的结果按照 Code 和ID 排序,在Over()子句中,按照Code分区,按照ID排序。

分析查询结果

1,当Code=1时

当Code=1时,在这个分区(窗口)中,有两行数据,ID分别是1,3

当Code=1,ID=1时,是分区的第一行,Count_Over=1,Sum_Over=1,这是滑动窗口的第一行,聚合值是的计算逻辑是

select count(0) as Count_Over,
sum(ID) as Sum_Over
from dbo.dt_test
where Code=1
and ID<=

当Code=1,ID=3时,是分区的第二行,Count_Over=2,Sum_Over=4,这是滑动窗口的第二行,聚合值是的计算逻辑是

select count(0) as Count_Over,
sum(ID) as Sum_Over
from dbo.dt_test
where Code=1
and ID<=

2,当Code=2时

当Code=2时,在这个分区中,有三种,ID分别是1,1,3

当Code=2,ID=1时,是分区的第一行,Count_Over=2,Sum_Over=2,这是滑动窗口的第一行,聚合值是的计算逻辑是

select count(0) as Count_Over,
sum(ID) as Sum_Over
from dbo.dt_test
where Code=
and ID<=1

当Code=2,ID=1时,是分区的第二行,Count_Over=2,Sum_Over=2,这是滑动窗口的第二行,聚合值是的计算逻辑是

select count(0) as Count_Over,
sum(ID) as Sum_Over
from dbo.dt_test
where Code=
and ID<=1

当Code=2,ID=3时,是分区的第三行,Count_Over=3,Sum_Over=5,这是滑动窗口的第三行,聚合值是的计算逻辑是

select count(0) as Count_Over,
sum(ID) as Sum_Over
from dbo.dt_test
where Code=
and ID<=3

四,基于滑动窗口的运算举例

例子1,对分区中的连续两行计算加和

计算逻辑是:在当前分区中,对当前行和其之后的1行数据计算加和;

select ID,Code,sum(code) over(partition by ID order by Code rows between current row and 1 following) as SumCode
from dbo.dt_test

例子2,对分区中的数据行,按照特定顺序,计算从第一行到当前行的累加值

计算逻辑是:从第一行到当前行,计算累加值

select ID,Code,
sum(code) over(partition by ID order by Code rows between unbounded preceding and current row) as SumCode_Rows,
sum(code) over(partition by ID order by Code range between unbounded preceding and current row) as SumCode_Range
from dbo.dt_test

参考文档:

OVER Clause (Transact-SQL)

SQL Server Window Function 窗体函数读书笔记二 - A Detailed Look at Window Functions

总结SQL Server窗口函数的简单使用

SQL Server中的窗口函数

Over:窗口函数(滑动聚合)的更多相关文章

  1. mysql滑动聚合

    滑动聚合是按顺序对滑动窗口范围内的数据进行聚合的操作.下累积聚合不同,滑动聚合并不是统计开始计算的位置到当前位置的数据. 这里以统计最近三个月中员工第月订单情况为例来介绍滑动聚合. 滑动聚合和累积聚合 ...

  2. hive常用函数 wordCount--Hive窗口函数1.1.1 聚合开窗函数聚合开窗函数实战

    第三天笔记 第三天笔记 SQL练习Hive 常用函数关系运算数值计算条件函数日期函数重点!!!字符串函数Hive 中的wordCount1.1 Hive窗口函数1.1.1 聚合开窗函数聚合开窗函数实战 ...

  3. 你真的会玩SQL吗?你所不知道的 数据聚合

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  4. Sql Server2005 Transact-SQL 窗口函数(OVER)

    1.简介: SQL Server 2005中的窗口函数帮助你迅速查看不同级别的聚合,通过它可以非常方便地累计总数.移动平均值.以及执行其它计算.窗口函数功能非常强大,使用起来也十分容易.可以使用这个技 ...

  5. SQL2005 学习笔记 窗口函数(OVER)【转】

    1.简介: SQL Server 2005中的窗口函数帮助你迅速查看不同级别的聚合,通过它可以非常方便地累计总数.移动平均值.以及执行其它计算. 窗口函数功能非常强大,使用起来也十分容易.可以使用这个 ...

  6. mysql年初至今聚合

    年初至今聚合和滑动聚合类似,不同的地方仅在于统计的仅为当前一年的聚合.唯一的区别体现在下限的开始位置上.在年初至今的问题中,下限为该年的第一天,而滑动聚合的下限为N个月的第一天.因此,年初至今的问题的 ...

  7. 第八章 SQL高级处理 8-1 窗口函数

    一.什么是窗口函数 窗口函数也称为LOAP函数.OnLine Analytical Processing的简称.意思是对数据库数据进行实时分析处理. 窗口函数就是为实现OLAP而添加的标准SQL功能. ...

  8. PostgreSQL 窗口函数 ( Window Functions ) 如何使用?

    一.为什么要有窗口函数 我们直接用例子来说明,这里有一张学生考试成绩表testScore: 现在有个需求,需要查询的时候多出一列subject_avg_score,为此科目所有人的平均成绩,好跟每个人 ...

  9. SQL进阶系列之0窗口函数

    窗口函数 What's 窗口函数? 窗口函数也称为OLAP(OnLine Analytical Processing)函数,目前MySQL还不支持. 窗口函数的语法 <窗口函数> OVER ...

随机推荐

  1. Linux SHELL 命令入门题目(一)

    新年新气象,注重知识积累,提高手敲代码能力,而不是眼高手低,只会复制黏贴. 1.使用shell 打印 “Hello World!” 2.求变量'hello world'的字符长度 3.$0 .$SHE ...

  2. css箭头

    .aui-list-item-arrow:before { content: ''; width: 0.4rem; height: 0.4rem; position: absolute; top: 5 ...

  3. docker学习之二镜像创建

    继上一篇docker入门之后写一点使用的经验. 通过命令:docker run -it REPOSITORY或IMAGE ID   注:-it后面跟的字段可以通过下面指令获得 创建运行的容器,会进入一 ...

  4. C#在Linux+Mono环境中使用微信支付证书

    最近特殊的需求,要把微信平台一个功能页面部署到Linux(CentOS6.5)下,其中涉及到微信支付退款. 鉴于之前实践过mono+jexus+asp.net mvc的部署,于是问题重点在于解决对商户 ...

  5. HTML常用标签总结

    HTML 的常用标签总结 <font size="字体大小1-7" color="red或0xff00ff" face="字体类型(楷体等)&q ...

  6. java分享第十七天-01(封装操作xml类)

    做自动化测试的人,都应该对XPATH很熟悉了,但是在用JAVA解析XML时,我们通常是一层层的遍历进去,这样的代码的局限性很大,也不方便,于是我们结合一下XPATH,来解决这个问题.所需要的JAR包: ...

  7. LL LR SLR LALR 傻傻分不清

    [转] 一:LR(0),SLR(1),规范LR(1),LALR(1)的关系     首先LL(1)分析法是自上而下的分析法.LR(0),LR(1),SLR(1),LALR(1)是自下而上的分析法.   ...

  8. 【转】POJ题目分类推荐 (很好很有层次感)

    OJ上的一些水题(可用来练手和增加自信) (poj3299,poj2159,poj2739,poj1083,poj2262,poj1503,poj3006,poj2255,poj3094)初期: 一. ...

  9. 常用的一些复杂SQL语句

    1.根据表中的birthday统计年龄段人数: //以下代码表示查询出来后的结果集添加一列字段 cast('20以下' as char) as age SELECT COUNT((DATE_FORMA ...

  10. spring的代理模式

    静态代理: 首先定义一个接口,随便写一个方法 定义2个实现接口的方法 (被代理的对象) (代理对象) 需要将接口 定义get set 方法 代理增强的方法 然后实现 输出结果如下: 动态代理(jdk动 ...