sql-server-2012 - SQL Server 2012 - 使用 OVER 的滑动函数

标签 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 [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/

相关文章:

sql-server - CS2001执行部署到服务器的SSIS包时缺少AssemblyAttributes.cs

visual-studio - 无法在 Visual Studio 中调试存储过程。 'Step Into Stored Procedure' 丢失

sql-server - 如何在 SQL Server 中使用 DACPAC 将可空列更新为不可空列

entity-framework - 如何使用 Entity Framework 在Sql Server Express中获取下一个序列号?

c# - 实体列表,最大日期,最大 row_id

c# - SQL Server 中数据更改时自动刷新应用程序

sql - 在 SQL Server 2012 中使用 MERGE 插入/更新数据

sql - 在 SQL Server 2012 中注册 CLR 函数(基于 WCF)

sql-server - 为 Windows Azure 虚拟机打开端口

sql-server - SSIS导入Excel数据