如何用LAG函数计算借贷方滚动余额?附会计表数据及错误尝试
嘿,我来帮你搞定这个滚动余额计算的问题~
你之前用LAG函数没成功,是因为LAG只能取前一行的特定值,没办法实现累计求和的逻辑——而滚动余额本质是按顺序累加所有借方(DR)、累加所有贷方(CR),再用累计借方减累计贷方得到的结果。
正确的解决思路
我们需要用窗口函数SUM() OVER()来计算累计DR和累计CR,然后基于这两个累计值算出余额,最后再根据余额的正负调整显示格式(比如正数加dr,负数加括号和cr)。
完整SQL代码(Oracle为例)
SELECT id, edate, discription, dr, cr, CASE WHEN balance_num > 0 THEN TO_CHAR(balance_num) || 'dr' WHEN balance_num < 0 THEN '(' || TO_CHAR(ABS(balance_num)) || ')cr' ELSE '0' END AS BALANCE FROM ( -- 先计算累计余额的数值 SELECT id, edate, discription, dr, cr, SUM(dr) OVER(ORDER BY id) - SUM(cr) OVER(ORDER BY id) AS balance_num FROM accounting ) t ORDER BY id;
代码解释
- 子查询里的
SUM(dr) OVER(ORDER BY id)会按ID顺序累加所有DR值,SUM(cr) OVER(ORDER BY id)同理累加CR值,两者相减就是当前行的滚动余额数值。 - 外层用
CASE语句处理显示格式:- 余额为正:显示数值加
dr - 余额为负:显示括号包裹绝对值加
cr - 余额为0:直接显示0
- 余额为正:显示数值加
验证结果
运行这段代码后,你会得到完全符合预期的输出:
| ID | EDATE | DISCRIPTION | DR | CR | BALANCE |
|---|---|---|---|---|---|
| 1 | 19-JAN-19 | cash in | 1000 | 0 | 1000dr |
| 2 | 19-JAN-19 | cash out | 0 | 200 | 800dr |
| 3 | 19-JAN-19 | cash in | 500 | 0 | 1300dr |
| 4 | 19-JAN-19 | cash out | 0 | 200 | 1100dr |
| 5 | 19-JAN-19 | cash out | 0 | 200 | 900dr |
| 6 | 19-JAN-19 | cash out | 0 | 1800 | (900)cr |
如果你用的是其他数据库(比如MySQL),只需要把字符串拼接的||换成CONCAT(),TO_CHAR()换成CAST(balance_num AS CHAR)就可以啦~
内容的提问来源于stack exchange,提问作者ali_codex
相关产品推荐
相关产品推荐

