在SQL中获取运行总计的最大值的高效方法

时间:2010-01-22 16:43:57

标签: sql-server tsql sql-server-2008 sql-server-2000

我们有一个交易表,其结构如下:

TranxID    int (PK and Identity field)
ItemID     int
TranxDate  datetime
TranxAmt   money

TranxAmt可以是正数或负数,因此该字段的运行总计(对于任何ItemID)将随着时间的推移而上下移动。获得当前总数显然很简单,但我所追求的是获得运行总计和TranxDate最高值的高效方法。请注意,TranxDate不是唯一的,并且由于某些回溯,ID字段不一定与给定项目的TranxDate序列相同。
目前我们正在做这样的事情(@tblTranx是一个只包含给定Item的事务的表变量):

SELECT Top 1 @HighestTotal = z.TotalToDate, @DateHighest = z.TranxDate
FROM
    (SELECT a.TranxDate, a.TranxID, Sum(b.TranxAmt) AS TotalToDate
    FROM @tblTranx AS a
    INNER JOIN @tblTranx AS b ON a.TranxDate >= b.TranxDate
    GROUP BY a.TranxDate, a.TranxID) AS z
ORDER BY z.TotalToDate DESC

(TranxID分组消除了重复日期值导致的问题)

对于一个Item,当发生这种情况时,它给出了HighestTotal和TranxDate。我们只是在应用程序更新相关条目并将值记录在另一个表中以用于报告时,而不是为数万个条目动态运行此值。

问题是,这可以以更好的方式完成,这样我们就可以动态计算出这些值(同时为多个项目)而不会陷入RBAR陷阱(某些ItemID有数百个条目)。如果是这样,那么是否可以对其进行调整以获得事务子集的最高值(基于上面未包括的TransactionTypeID)。我目前正在使用SQL Server 2000,但SQL Server 2008将很快接管,因此可以使用任何SQL Server技巧。

1 个答案:

答案 0 :(得分:3)

SQL Server计算跑步总数很糟糕。

以下是您的查询的解决方案(按日期分组):

WITH    q AS
        (
        SELECT  TranxDate, SUM(TranxAmt) AS TranxSum
        FROM    t_transaction
        GROUP BY
                TranxDate
        ),
        m (TranxDate, TranxSum) AS
        (
        SELECT  MIN(TranxDate), SUM(TranxAmt)
        FROM    (
                SELECT  TOP 1 WITH TIES *
                FROM    t_transaction
                ORDER BY
                        TranxDate
                ) q
        UNION ALL
        SELECT  DATEADD(day, 1, m.TranxDate),
                m.TranxSum + q.TranxSum
        FROM    m
        CROSS APPLY
                (
                SELECT  TranxSum
                FROM    q
                WHERE   q.TranxDate = DATEADD(day, 1, m.TranxDate) 
                ) q
        WHERE   m.TranxDate <= GETDATE()
        )
SELECT  TOP 1 *
FROM    m
ORDER BY
        TranxSum DESC
OPTION (MAXRECURSION 0)

需要TranxDate上设置索引才能使其快速运行。