lag函数本身不直接计算期初余额,需先显式插入期初行,再用lag(ending_balance)取上一行期末值作为期初值,并配合first_value和coalesce确保首行不为空。

LAG函数本身不直接算期初余额,但能稳定承接期初值传递
很多人误以为 LAG() 可以“自动拿到期初”,其实它只是个取值工具。真正起作用的是:你先把期初余额作为第一行插入数据流(比如用 UNION ALL 插入 '2024-01-01' 行),再用 LAG(ending_balance) 向前取上一行的期末值——这一行恰好就是期初值。关键不是 LAG 多聪明,而是它让“期初 = 上日期末”这个业务逻辑有了可落地的窗口表达。
不用LAG时常见的期初错位问题
直接对原始交易表跑 FIRST_VALUE(balance) OVER (PARTITION BY account_id ORDER BY trans_date) 容易出错,原因包括:
-
trans_date有重复时,数据库可能任意选一条当“first”,结果不可控 - 原始表里根本没存期初余额,
FIRST_VALUE只能从第一笔交易开始取,漏掉期初静态值 - 没显式写
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,默认帧只到当前行,首行也拿不准
LAG配合FIRST_VALUE才是稳妥组合
典型做法是三步走:
- 先用
UNION ALL把期初行(如trans_date = '2024-01-01', amount = 5000)插到最前面 - 用
FIRST_VALUE(amount) OVER (ORDER BY trans_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)提取这个固定期初值 - 用
SUM(amount) OVER (ORDER BY trans_date)算累计变动,得到每日期末;再用LAG(ending_balance)得到次日期初 - 必须加
COALESCE(LAG(...), FIRST_VALUE(...)),否则第一行期初会是NULL
ORDER BY字段不唯一或含NULL时LAG会失效
LAG() 依赖稳定的排序,如果 ORDER BY trans_date 中存在重复日期或 NULL 值,同一组内行序不确定,LAG 取的“上一行”就可能跳变。实际中建议:
- 把主键或自增
id加进ORDER BY,写成ORDER BY trans_date, id - 对空日期用
COALESCE(trans_date, '1970-01-01')填充,避免NULL干扰排序稳定性 - 若业务允许,优先在应用层补全日期序列(如用
GENERATE_SERIES),再做LAG,比硬扛缺失更可控
LAG 语法,而是让每一行的“上一行”在业务语义上确实对应“上一日期末”。这要求数据源干净、排序键唯一、期初值显式注入——缺一不可。










