假设我有以下架构:
-- 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 仅支持 OVER 子句中的 PRECEDING 和 FOLLOWING 整数文字。
有两个选项可供您选择:动态 sql 和重写查询以不使用 PRECEDING
动态 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
关于sql-server-2012 - SQL Server 2012 - 使用 OVER 的滑动函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14508673/