SQL实现累计余额计算:当前Balance累加上一行Balance
解决逐行累计余额的SQL实现问题
你的现有查询问题出在使用了GROUP BY——这是做分组聚合,而不是你需要的逐行累加计算,所以自然得不到预期的累计余额结果。下面给你一个符合需求的正确实现方案:
核心思路
要实现「当前行Balance + 上一行Balance」的累计效果,我们需要:
- 先正确计算每行的单独Balance(处理NULL值,确保计算逻辑准确);
- 使用窗口函数
SUM() OVER()来实现逐行累加的运行总计(Running Total); - 给每行指定明确的顺序(SQL表本身是无序的,必须保证累加顺序和你预期的一致)。
完整SQL代码
declare @tab table(Debit int,Credit int) insert into @tab select 1000 , NULL union all select 2200 , NULL union all select NULL , 3000 union all select 1500 , 1500 -- 生成带累计余额的结果集 SELECT Debit, Credit, -- 计算当前行的单笔余额:Debit为收入,Credit为支出,NULL视为0 ISNULL(Debit, 0) - ISNULL(Credit, 0) AS Balance, -- 逐行累加的累计余额:从第一行到当前行的Balance总和 SUM(ISNULL(Debit, 0) - ISNULL(Credit, 0)) OVER (ORDER BY RowNum) AS CumulativeBalance FROM ( -- 先给每行分配行号,确保累加顺序和插入顺序一致(如果有其他排序字段可替换这里的ORDER BY) SELECT Debit, Credit, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RowNum FROM @tab ) AS t
代码解释
- 行号分配:内层查询用
ROW_NUMBER()给每行加唯一行号,ORDER BY (SELECT NULL)在SQL Server中会遵循数据插入的顺序排序;如果你有业务上的排序字段(比如交易日期),把这里替换成对应的字段即可。 - 单笔Balance计算:用
ISNULL(Debit, 0) - ISNULL(Credit, 0)处理NULL值,把空值视为0,符合常规的财务逻辑(收入减支出)。如果你的Balance逻辑是原查询里的「有Credit取Credit,否则取Debit」,可以把这部分改成COALESCE(Credit, Debit),但注意这可能不符合常规的收支计算逻辑。 - 累计余额计算:
SUM(...) OVER (ORDER BY RowNum)是窗口函数,它会计算从第一行到当前行的Balance总和,完美实现你要的逐行累加效果。
执行结果示例
| Debit | Credit | Balance | CumulativeBalance |
|---|---|---|---|
| 1000 | NULL | 1000 | 1000 |
| 2200 | NULL | 2200 | 3200 |
| NULL | 3000 | -3000 | 200 |
| 1500 | 1500 | 0 | 200 |
内容的提问来源于stack exchange,提问作者Doonie Darkoo
相关产品推荐
相关产品推荐

