递归SQL-如何获得具有运行总计的此表?

时间:2013-06-11 17:59:07

标签: sql sql-server

ID      debit   credit  sum_debit
---------------------------------
1       150     0       150
2       100     0       250
3       0       50      200
4       0       100     100
5       50      0       150

我有这个表格,我的问题是如何获取sum_debit列,这是前一行sum_debit的总和,借记减去信用(sum_debit = sum_debit + debit - credit)。 每个新行我输入借方但信用数据为零,或者输入信用值和借方为零。我如何获得sum_debit

2 个答案:

答案 0 :(得分:4)

在SQL-Server 2012中,您可以使用新添加的ROWS or RANGE子句:

SELECT 
    ID, debit, credit,
    sum_debit = 
        SUM(debit - credit) 
        OVER (ORDER BY ID
              ROWS BETWEEN UNBOUNDED PRECEDING
                       AND CURRENT ROW
             )
FROM 
    CreditData
ORDER BY
    ID ;

SQL-Fiddle

中进行测试

我们可以在那里使用OVER(ORDER BY ID),结果也是一样的。但是然后会使用默认值RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW并且存在效率差异(ROWS应该首选运行总计。)

@Aaron Bertrand有一篇很棒的文章,对各种计算累计总计的方法进行了全面测试: Best approaches for running totals – updated for SQL Server 2012


对于以前版本的SQL-Server,您必须使用其他方法,例如自联接,递归CTE或游标。这是一个光标解决方案,盲目地从Aaron的博客中复制,表格和列根据您的问题调整:

DECLARE @cd TABLE
(   [ID] int PRIMARY KEY, 
    [debit] int, 
    [credit] int,
    [sum_debit] int
);

DECLARE
    @ID           INT,
    @debit        INT,
    @credit       INT,
    @RunningTotal INT = 0 ;

DECLARE c CURSOR
    LOCAL STATIC FORWARD_ONLY READ_ONLY
    FOR
    SELECT ID, debit, credit
      FROM CreditData
      ORDER BY ID ;

OPEN c ;

FETCH NEXT FROM c INTO @ID, @debit, @credit ;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @RunningTotal = @RunningTotal + (@debit - @credit) ;

    INSERT @cd (ID, debit, credit, sum_debit )
        SELECT @ID, @debit, @credit, @RunningTotal ;

    FETCH NEXT FROM c INTO @ID, @debit, @credit ;
END

CLOSE c;
DEALLOCATE c;

SELECT ID, debit, credit, sum_debit
    FROM @cd
    ORDER BY ID ;

SQL-Fiddle-cursor

中进行测试

答案 1 :(得分:2)

假设“have”是您的数据表,这应该是ANSI SQL解决方案:

select h.*, sum(i.debit) as debsum, sum(i.credit) as credsum, sum(i.debit) - sum(i.credit) as rolling_sum
from have h inner join have i
on h.id >= i.id
group by h.id, h.debit, h.credit
order by h.id

通常,解决方案是将行连接到行之前的所有行,然后提取这些行的总和,然后按所有内容进行分组,以按照预期返回到一行。例如this question