SQL运行总计计算中如何按交易类型分别实现加减运算
带加减逻辑的运行总计(累计余额)实现方案
不需要针对不同交易类型单独写分支累加逻辑,只需要先将单行交易金额根据类型转换为带正负符号的计算值,再基于转换后的值做窗口累计求和即可。
正确实现代码
SELECT ROW_NUMBER() OVER (ORDER BY DOT ASC) AS RNO, DOT, TXN_TYPE, CHQ_NO, TXN_AMOUNT, SUM( CASE -- 现金取款类型金额取负,累加时等价于扣减 WHEN TXN_TYPE = 'CW' THEN -TXN_AMOUNT -- 现金存款、支票存款类型保持正金额累加 ELSE TXN_AMOUNT END ) OVER ( ORDER BY DOT ASC -- 明确窗口范围,避免不同数据库默认窗口规则差异导致结果异常 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS running_total FROM TransactionMaster WHERE DATEDIFF(YY, dot, GETDATE()) <= 2 AND acid = 4 -- 若查询场景为明细查询无重复数据,可删除下面的GROUP BY GROUP BY DOT, TXN_TYPE, CHQ_NO, TXN_AMOUNT
逻辑说明
- 金额转换规则:
- 交易类型为
CW(现金取款)时,将交易金额转为负数,累计时自动从余额中扣减对应金额 - 交易类型为
CD(现金存款)、CHQ(支票存款)时,保持交易金额为正数,累计时自动加到余额中
- 交易类型为
- 窗口函数按交易时间
DOT排序,逐行计算从第一笔交易到当前行的带符号金额总和,直接得到累计余额。 - 如果存在同一交易时间点多笔交易的情况,建议在
ORDER BY后补充唯一交易标识(如交易流水号),避免排序随机导致累计结果错误。 - 如果账户有初始余额,只需要在SUM窗口计算结果后直接加上初始余额数值即可,即可匹配你给出的37385.00、6437、108818的序列计算结果。
原代码问题说明
- 核心逻辑错误:原写法对不同交易类型单独调用
SUM() OVER()累加原始正金额,没有对取款类交易做金额取负,完全没有实现减法逻辑。 - 语法错误:CASE分支中嵌套查询的写法不符合SQL语法规范,且逐行关联子查询会导致查询性能随数据量上升急剧下降。
- 笔误:原代码中将
CHQ(支票存款)错写为CQD,会导致该类交易的判断逻辑失效。
内容的提问来源于stack exchange,提问作者vamsi tummala
相关产品推荐
相关产品推荐

