Sql server 2012 SQL Server 2012-使用OVER的滑动函数
假设我有以下模式:Sql server 2012 SQL Server 2012-使用OVER的滑动函数,sql-server-2012,Sql Server 2012,假设我有以下模式: -- Create the dbo.Transaction table CREATE TABLE [dbo].[Transaction] ( [TransactionId] INT NOT NULL IDENTITY, [AccountId] INT NOT NULL, [TransactionDate] DateTime2(7) NOT NULL, [Amount] decimal(9,3) NOT NULL CONSTRAINT [
-- Create the dbo.Transaction table
CREATE TABLE [dbo].[Transaction] (
[TransactionId] INT NOT NULL IDENTITY,
[AccountId] INT NOT NULL,
[TransactionDate] DateTime2(7) NOT NULL,
[Amount] decimal(9,3) NOT NULL
CONSTRAINT [PK_Transaction] PRIMARY KEY ([TransactionId])
);
以及以下查询:
Select
AccountId,
TransactionDate,
Amount,
AverageAmount = Avg(Amount) Over (Partition By AccountId Order By TransactionDate ROWS BETWEEN 2 PRECEDING AND CURRENT ROW),
TransactionCount = Count(Amount) Over (Partition By AccountId Order By TransactionDate ROWS 2 PRECEDING),
MinimumAmount = Min(Amount) Over (Partition By AccountId Order By TransactionDate ROWS 2 PRECEDING),
MaximumAmount = Max(Amount) Over (Partition By AccountId Order By TransactionDate ROWS 2 PRECEDING),
SumAmount = Sum(Amount) Over (Partition By AccountId Order By TransactionDate ROWS 2 PRECEDING)
From dbo.[Transaction]
Order By AccountId, TransactionDate
如果查询包含在UDF或存储过程中,并且滑动间隔(在本例中为2)直到运行时才作为参数传递给UDF/存储过程,我将如何执行该查询?SQL 2012似乎不允许在此处使用变量。如您所述,SQL Server只支持前面和后面in-OVER子句的整数文本 有两个选项可供选择:动态sql和重新编写查询以不使用前面的语句 动态sql是最简单的,但我会小心地将其放在UDF中
set @sql = N'Select AccountId, ... ROWS '
+ cast(@sz as varchar(10)) + N' PRECEDING) ...'
exec sp_executesql @sql
然而,窗口函数只是花哨的语法。您可以在不使用它们的情况下重新编写查询:
DECLARE @sz INT
SET @sz = 2
;
WITH q AS ( SELECT AccountId ,
TransactionDate ,
Amount ,
ROW_NUMBER() OVER ( PARTITION BY AccountId
ORDER BY TransactionDate ) rw
FROM [Transaction]
)
SELECT accountID ,
TransactionDate ,
Amount ,
( SELECT AVG(q1.Amount) FROM q q1
WHERE q1.accountid = q.accountid
AND q1.rw BETWEEN q.rw - @sz AND q.rw
) AverageAmount,
( SELECT COUNT(q1.Amount) FROM q q1
WHERE q1.accountid = q.accountid
AND q1.rw BETWEEN q.rw - @sz AND q.rw
) TransactionAmount
-- etc.
FROM q
ORDER BY AccountID, TransactionDate
这里还有另一种重新编写查询的方法:
DECLARE @sz INT
SET @sz = 2;
WITH q AS ( SELECT AccountId ,
TransactionDate ,
Amount ,
ROW_NUMBER() OVER ( PARTITION BY AccountId
ORDER BY TransactionDate ) rw
FROM [Transaction]
)
SELECT q.accountID ,
q.TransactionDate ,
q.Amount ,
AVG(q1.Amount) AverageAmount ,
COUNT(q1.Amount) TransactionAmount ,
MAX(q1.Amount) MaxAmount ,
MIN(q1.Amount) MinAmount
-- etc.
FROM q
INNER JOIN q q1 ON q1.accountid = q.accountid
AND q1.rw BETWEEN q.rw - @sz AND q.rw
GROUP BY q.accountid ,
q.transactiondate ,
q.amount
聪明的解决方法,但调用窗口函数来实现“奇特的语法”有点不公平。对于windows函数,查询使用一个
windows spool
来执行移动窗口的工作,并且由于over子句对于所有聚合都是相同的,因此只有一个表扫描(如果有覆盖索引,则为索引扫描)。您的解决方案将有6个表/索引扫描。巨大的区别。我将前面提到的语法称为花哨的语法的观点是,不使用语法就可以编写逻辑上等价的查询。我还添加了一种额外的方法来重新编写查询,以减少扫描次数。是的,当使用上一个查询时,Sql可能会提供更好的物理计划,但逻辑上查询是相同的。解决方法很好,但由于额外的开销,仍然很痛苦。我想知道这是否可能与一个可变的窗口规范。。。可能不会。但在某些情况下,例如年初至今的计算,这样的滑动窗口规范将非常受欢迎。