如何计算表中每行Opening值为上一行Opening与Transfer之和?
重新计算Opening列的高效方案
你的核心需求是:当前行的Opening = 上一行的Opening + 上一行的Transfer,第一行Opening为初始值。不需要用游标或while循环,窗口函数或递归CTE是更高效、简洁的实现方式,前提是你的表有一个能确定行顺序的字段(比如自增row_id)。
方案1:使用窗口函数(MySQL 8.0+/PostgreSQL/SQL Server)
用LAG()函数直接获取上一行的Opening值,结合计算逻辑生成正确的Opening:
SELECT CASE WHEN row_id = 1 THEN Opening ELSE LAG(Opening) OVER (ORDER BY row_id) + LAG(Transfer) OVER (ORDER BY row_id) END AS Opening, Transfer FROM your_table ORDER BY row_id;
或者用累计求和的方式,逻辑等价但更简洁:
SELECT (SELECT Opening FROM your_table WHERE row_id = 1) + COALESCE(SUM(Transfer) OVER (ORDER BY row_id ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) AS Opening, Transfer FROM your_table ORDER BY row_id;
方案2:递归CTE(支持递归的数据库)
如果需要更贴合“逐行计算”的逻辑,递归CTE是直观的选择:
WITH cte AS ( -- 第一行作为初始数据 SELECT row_id, Opening, Transfer FROM your_table WHERE row_id = 1 UNION ALL -- 递归计算后续行 SELECT t.row_id, c.Opening + c.Transfer AS Opening, t.Transfer FROM your_table t JOIN cte c ON t.row_id = c.row_id + 1 ) SELECT Opening, Transfer FROM cte ORDER BY row_id;
方案3:旧版MySQL(无窗口函数)
如果使用MySQL 5.x这类不支持窗口函数的版本,用用户变量实现:
-- 初始化变量为第一行的Opening值 SET @prev_opening = (SELECT Opening FROM your_table WHERE row_id = 1); SELECT @prev_opening AS Opening, Transfer, -- 更新变量,供下一行计算使用 @prev_opening := @prev_opening + Transfer FROM your_table ORDER BY row_id;
为什么游标/while循环容易失效?
- 游标需要手动处理行顺序、变量更新,稍有疏忽就会出现逻辑错误(比如漏更改变量、顺序判断错误)
- While循环依赖
id的连续性,如果表中存在删除行导致id断号,循环会直接终止,而上述方案只需要排序字段存在,不依赖id连续
测试结果
用你的示例数据验证,以上方案都会输出正确的表格:
| Opening | Transfer |
|---|---|
| 0 | 12 |
| 12 | -2 |
| 10 | -2 |
| 8 | -1 |
| 7 | -7 |
内容的提问来源于stack exchange,提问作者Jordan P
相关产品推荐
相关产品推荐

