Rav*_*avi 1 sql-server-2008 sql-server
这是 MSDN 页面上 OVER 子句的一段代码:
USE AdventureWorks2012;
GO
SELECT BusinessEntityID, TerritoryID
,DATEPART(yy,ModifiedDate) AS SalesYear
,CONVERT(varchar(20),SalesYTD,1) AS SalesYTD
,CONVERT(varchar(20),AVG(SalesYTD) OVER (PARTITION BY TerritoryID
ORDER BY DATEPART(yy,ModifiedDate)
),1) AS MovingAvg
,CONVERT(varchar(20),SUM(SalesYTD) OVER (PARTITION BY TerritoryID
ORDER BY DATEPART(yy,ModifiedDate)
),1) AS CumulativeTotal
FROM Sales.SalesPerson
WHERE TerritoryID IS NULL OR TerritoryID < 5
ORDER BY TerritoryID,SalesYear;
Run Code Online (Sandbox Code Playgroud)
所以我在理解为什么必须在那里使用 CONVERT 函数时遇到问题。我认为这与转换函数的表达式部分中的字段之一的返回类型有关?可以用 CAST 代替吗?我的第二个问题是,这部分究竟是如何工作的?
SUM(SalesYTD) OVER (PARTITION BY TerritoryID
ORDER BY DATEPART(yy,ModifiedDate)
Run Code Online (Sandbox Code Playgroud)
这到底是什么意思?是每年计算总和吗?是这样吗?
转换样式
如果 SalesYTD 类型是浮点数或实数:
1 = 总是 8 位数字。始终使用科学记数法。
如果类型是钱和小钱:
1 = 小数点左边每三位逗号,小数点右边两位;例如,3,510.92。
Cast 将使用样式的默认值:0
如果 SalesYTD 类型是浮点数或实数:
0(默认)= 最多 6 位数字。适当时使用科学记数法。
如果类型是钱和小钱:
0(默认)= 小数点左边每三位数字无逗号,小数点右边两位数字;例如,4235.98。
与其他类型的样式还有其他差异和默认值,但我认为它涵盖了您的数据类型。请参阅CAST 和 CONVERT (Transact-SQL)
SUM窗函数
对于每个分区 (=TerritoryID),它需要所有 SalesYTD,按 DATEPART(yy,ModifiedDate) 对它们进行排序并将它们相加。请注意,订单部分不是必需的,也可以是任何东西,因为您只执行 SUM 和 AVG,但使用它会改变行为(请参阅有关它的超立方体答案和移动平均线)。对于 ROW_NUMBER 和其他人,这将是重要且强制性的。
SUM 和移动 SUM 之间的区别(@hypercube 答案):
declare @data table(TerritoryID int, SalesYTD int, ModifiedDate date)
insert into @data(TerritoryID, SalesYTD, ModifiedDate) values
(1, 1, '20100101')
, (1, 2, '20110101')
, (1, 3, '20120101')
, (1, 4, '20130101')
, (1, 5, '20140101')
, (2, 6, '20150101')
, (2, 7, '20160101')
, (2, 8, '20170101')
Select *
, [Moving SUM] = SUM(SalesYTD) OVER (PARTITION BY TerritoryID ORDER BY DATEPART(yy,ModifiedDate))
, [SUM] = SUM(SalesYTD) OVER (PARTITION BY TerritoryID)
From @data
Run Code Online (Sandbox Code Playgroud)
输出:
TerritoryID | SalesYTD | ModifiedDate | Moving SUM | SUM
---------------------------------------------------------------------
1 | 1 | 2010-01-01 | 1 => 1 | 10 => 1+2+3+4
1 | 2 | 2011-01-01 | 3 => 1+2 | 10 => 1+2+3+4
1 | 3 | 2012-01-01 | 6 => 1+2+3 | 10 => 1+2+3+4
1 | 4 | 2013-01-01 | 10 => 1+2+3+4 | 10 => 1+2+3+4
2 | 6 | 2015-01-01 | 6 => 6 | 21 => 6+7+8
2 | 7 | 2016-01-01 | 13 => 6+7 | 21 => 6+7+8
2 | 8 | 2017-01-01 | 21 => 6+7+8 | 21 => 6+7+8
Run Code Online (Sandbox Code Playgroud)
有关窗口函数,请参阅OVER 子句 (Transact-SQL)。
关于窗口聚集体(SUM()
和AVG()
与OVER (...)
:
SUM(SalesYTD) OVER (PARTITION BY TerritoryID
ORDER BY DATEPART(yy,ModifiedDate))
Run Code Online (Sandbox Code Playgroud)
MSDN页面OVER
条款(Transact-SQL)有这个(相当隐藏)的评论:
一般备注
...
如果ORDER BY
未指定整个分区用于窗口框架。这仅适用于不需要ORDER BY
子句的函数。如果ROWS/RANGE
未指定但ORDER BY
已指定,RANGE UNBOUNDED PRECEDING AND CURRENT ROW
则用作窗口框架的默认值。这仅适用于可以接受可选ROWS/RANGE
规范的函数。例如,排名函数不能接受ROWS/RANGE
,因此即使ORDER BY
存在和ROWS/RANGE
不存在,也不应用此窗口框架。
这意味着您上面的代码具有与以下相同的结果:
SUM(SalesYTD) OVER (PARTITION BY TerritoryID
ORDER BY DATEPART(yy, ModifiedDate)
RANGE BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
Run Code Online (Sandbox Code Playgroud)
因此,SUM()
通过获取所有具有相同TerritoryID
且年份部分ModifiedDate
小于或等于行的年份部分的行来计算(对于一行)。这通常称为“累积总计”,因为它包含从起始值(示例中的最小年份)到当前值(年份)(所有行)的所有值的总计。这同样适用于AVG()
计算(通常称为“移动平均线”。
归档时间: |
|
查看次数: |
139 次 |
最近记录: |