LAG函数必须配合OVER (ORDER BY)才能可靠取上一行,否则结果随机;默认偏移量为1,支持指定偏移量和默认值;首行及分组首行返回NULL属正常,宜用COALESCE兜底;不可在WHERE或GROUP BY中直接引用,须用子查询或CTE;ORDER BY字段应建索引以防性能下降。

LAG函数的基本用法和必要参数
LAG 是窗口函数,不能脱离 OVER 子句单独使用。最简可用形式是 LAG(column_name),它默认取上一行的值,但必须配合 ORDER BY 明确排序逻辑,否则结果不可预测。
- 不写
ORDER BY会报错或返回随机行 —— SQL Server 和 PostgreSQL 都强制要求,MySQL 8.0+ 同样如此 -
LAG默认偏移量为 1,即上一行;想取上两行就写LAG(column_name, 2) - 第三参数是默认值,当没有上一行时(比如第一行),返回该值;不提供则返回
NULL
例如:LAG(sales_amount, 1, 0) OVER (ORDER BY order_date) 表示按日期排序,取前一笔销售额,缺值时填 0。
ORDER BY 不匹配业务顺序会导致数据错位
常见错误是只按主键或时间戳排序,但没考虑业务意义上的“上一条”。比如订单表里 order_id 自增,但实际处理顺序可能按 created_at + user_id 分组内排序。
- 若需“每个用户最近一笔订单的金额”,必须写成
OVER (PARTITION BY user_id ORDER BY created_at) - 如果漏掉
PARTITION BY,所有用户混在一起排序,LAG就会跨用户取值 - 时间字段存在重复值时,
ORDER BY created_at可能不稳定,建议加二级排序如ORDER BY created_at, order_id
LAG 返回 NULL 的几种典型场景
LAG 在首行、分组首行、或偏移超出范围时返回 NULL,但这不是 bug,而是设计行为。是否需要处理,取决于业务逻辑。
- 第一行永远没“上一行”,所以
LAG必然为NULL(除非设了默认值) -
PARTITION BY后每个分组独立计算,每组第一行同样返回NULL或默认值 - 如果用了
LAG(col, 3),但当前行前面只有 2 行,也会返回NULL(或默认值) - 别直接在
WHERE里过滤LAG(...) IS NOT NULL—— 这会丢掉首行数据,应先用子查询或 CTE 包一层再过滤
性能与索引注意事项
LAG 本身不慢,但排序开销大。执行计划里若出现 WindowAgg 或 Sort 节点耗时高,问题大概率出在 ORDER BY 字段没索引。
- 确保
OVER中的ORDER BY列有索引,尤其是组合排序字段(如(user_id, created_at)) - 避免在
LAG表达式里套复杂计算,比如LAG(CASE WHEN ... THEN ... END),先算好再窗口操作更清晰 - PostgreSQL 中
LAG支持帧定义(ROWS BETWEEN ...),但绝大多数场景不需要,加了反而限制优化器选择
真正容易被忽略的是:LAG 的结果依赖整个结果集的排序顺序,而这个顺序可能被外层 ORDER BY 或应用层再次打乱 —— 如果后续还要排序,务必确认窗口排序和最终展示顺序是否一致。










