设为首页 加入收藏

TOP

锋利的SQL2014:基于窗口的聚合计算(二)
2015-11-21 01:30:42 来源: 作者: 【 】 浏览:1
Tags:锋利 SQL2014 基于 窗口 聚合 计算

0.0909

2013

2

2

250

0.1136

2013

3

1

300

0.1363

2013

3

2

350

0.159

2013

4

1

400

0.1818

2013

4

2

450

0.2045

2014

1

1

200

0.1428

2014

1

2

250

0.1785

2014

2

1

200

0.1428

2014

2

2

250

0.1785

2014

3

1

100

0.0714

2014

3

2

150

0.1071

2014

4

1

100

0.0714

2014

4

2

150

0.1071

两条语句的执行结果虽然一样,但是工作原理却并不相同。对于分区而言,它会按照指定的分区列(SalesYear)一次分隔计算完毕,也就是说,这些独立的小窗口是同时存在的,如图9-2所示;而对于子查询,却需要为每行数据执行一次表扫描。不言而喻,两者的效率是存在差异的。

\

图9-2 分区后的所有窗口是同时存在的

9.2.2 窗口的排序与框架

框架可以对窗口进行进一步的分区,对于开窗聚合函数而言,按什么元素排序是至关重要的,排序一旦确定,框架的范围也就确定了下来。框架有两种范围限定方式,一种是使用ROWS子句通过指定当前行之前或之后的固定数目的行来限制分区中的行数,另一种是使用RANGE子句按照排序列的当前值,根据相同值来确定分区中的行数。例如,ROWS限定范围为当前行和前一行,那应当有两行数据;RANGE也是把范围限定为当前行和前一行,如果前一行的值与再前面行的值相同,那这个范围会自动扩大到3行。

1.ROWS子句

首先来看ROWS子句的语法格式:

ROWS BETWEEN UNBOUNDED PRECEDING |

< n > PRECEDING|

< n > FOLLOWING|

CURRENT ROW

AND

UNBOUNDED FOLLOWING |

< n >PRECEDING |

< n >FOLLOWING |

CURRENT ROW

UNBOUNDED PRECEDING指定窗口从分区中的第一行开始。< n > PRECEDING和< n > FOLLOWING分别用于指定窗口从当前行之前和之后的n行开始。CURRENT ROW用于指定当前行。UNBOUNDED FOLLOWING指定窗口在分区的最后一行结束。

下面通过一个示例来说明ROWS子句的使用方法,下面的语句按销售年度和雇员ID列进行分区,对于每个雇员累积计算第1季度至当前季度的销售额。查询结果和每次的累积分区窗口如图9-3所示。

SELECT EmpID, SalesYear, SalesQuarter, SubTotal,

SUM(SubTotal) OVER(PARTITION BY SalesYear, EmpID

ORDER BY SalesYear,SalesQuarter

ROWS BETWEEN UNBOUNDEDPRECEDING

AND CURRENTROW) AS RunSub

FROM dbo.Orders;

\

上面语句中的CURRENTROW限定也可以省略,SQLServer将默认把当前行作为框架的限定,参考下面的语句。

SELECT EmpID, SalesYear, SalesQuarter, SubTotal,

SUM(SubTotal) OVER(PARTITION BY SalesYear, EmpID

ORDER BY SalesYear,SalesQuarter

ROWS UNBOUNDED PRECEDING) AS RunSub

FROM dbo.Orders;

再来看另外一个示例,下面的语句使用< n > PRECEDING和< n > FOLLOWING通过指定具体行数的方法进行范围限定。第一个聚合中上限和下限都是当前行的前一行,实际上只有一行,用于取出当前季度上一季度的销售额;第二个聚合中上限和下限都是当前行的后一行,实际上也是只有一行,用于取出当前季度下一季度的销售额,第三个聚合中,上限是当前行的前一行,下限是当前行的后一行,实际上是取出当前季度与上一季度和下一季度的平均值。语句中的MAX函数只是为了语法上的合法性,该函数在数据处理上不起任何作为,因为范围内只有一行,没有什么值大小之说。查询结果如表9-6所示。

SELECT EmpID, SalesYear, SalesQuarter,

MAX(SubTotal) OVER(PARTITION BY EmpID

ORDER BY EmpID,SalesYear, SalesQuarter

ROWS BETWEEN 1 PRECEDING

AND 1 PRECEDING)AS N'上季度',

SubTotal AS N'当前季度',

MAX(SubTotal) OVER(PARTITION BY EmpID

ORDER BY EmpID,SalesYear, SalesQuarter

ROWS BETWEEN 1 FOLLOWING

AND 1 FOLLOWING) AS N'下季度',

AVG(SubTotal) OVER(PARTITION BY EmpID

ORDER BY EmpID,SalesYear, SalesQuarter

ROWS BETWEEN 1 PRECEDING

AND 1FOLLOWING) AS N'当前及上下季度平均'

FROM dbo.Orders;

\

分析一下表9-6中的数据。从第1行和第9行可以看出,对于2013年1季度而言,雇员1和雇员2在上一季度是没有数据的,故而是NULL值。从第8行和最后一行可以看出,对于2014年第4季度,之后也是没有数据的,因此也是NULL。看一下第1行中的平均值,它实际上是当前行和后一行的平均值,因为上一季度没有数据。第4行的平均值300,我们使用大括号的方式列出了它的计算范围,分别来自于300、400和200这三个数值。

2.RANGE子句

RANGE子句的语法格式与ROWS子句是基本相同的,唯一的区别是ROWS根据指定的行数来限定范围,而RANGE是根据排序列的值来确定范围。RANG子句的语法格式如下,但是截至SQL Server 2014为止,仅支持UNBOUNDED PRECEDING和CURRENT ROW操作符。

ROWS BETWEEN UNBOUNDED PRECEDING |

< val > PRECEDING |

< val > FOLLOWING |

CURRENT ROW

AND

UNBOUNDED FOLLOWING |

< val > PRECEDING |

< val > FOLLOWING |

CURRENT ROW

下面通过一个示例来说明RANGE子句的范围限定方法,参考下面的语句:

SELECT EmpID, SalesYear, SalesQuarter, SubTotal,

SUM(SubTotal)OVER(PARTITION BY EmpID

ORDER BY EmpID, SalesYear

RANGE BETWEEN UNBOUNDEDPRECEDING

AND CURRENT ROW) AS RunSubTotal

FROM dbo
首页 上一页 1 2 3 4 下一页 尾页 2/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇锋利的SQL2014:基于窗口的分布计.. 下一篇报表开发实例――动态多层次KPI钻..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: