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

LAG函数的基本用法和必需的ORDER BY
LAG不能在没有明确排序的查询里可靠工作——它不认“物理行序”,只按ORDER BY定义的逻辑顺序取上一行。漏写ORDER BY会导致结果随机,尤其在分布式或并行执行环境下。
- 必须搭配
OVER (ORDER BY ...),比如LAG(sales_amount) OVER (ORDER BY order_date) - 如果想按分组分别取上一行,加
PARTITION BY,例如LAG(price) OVER (PARTITION BY product_id ORDER BY update_time) - 默认取前1行,但可指定偏移量:
LAG(value, 2)取上上行,LAG(value, 1, 0)把首行缺失值补成0
NULL问题:为什么第一行总是NULL?
LAG对排序后第一行无“上一行”,返回NULL是正常行为,不是错误。但业务常需兜底,直接用COALESCE最稳妥。
- 写成
COALESCE(LAG(amount) OVER (ORDER BY id), 0)比在应用层判空更安全 - 避免用
IS NULL再套子查询,性能差且易出错 - 注意:
LAG(col, n, default_val)第三个参数仅在n步内无数据时生效,不覆盖所有NULL场景(比如n=2时第2行仍可能是NULL)
常见错误:在WHERE或GROUP BY里直接引用LAG结果
LAG是窗口函数,执行阶段晚于WHERE和GROUP BY,这两处直接写LAG(...)会报错或逻辑错乱。
- 想过滤LAG计算后的值?必须用子查询或CTE,例如:
SELECT * FROM (SELECT *, LAG(x) OVER (ORDER BY y) AS prev_x FROM t) t2 WHERE prev_x > 10
-
GROUP BY不能包含LAG表达式,但可以GROUP BY原始字段后再套窗口函数 - MySQL 8.0+、PostgreSQL、SQL Server都遵循这个执行顺序,别指望兼容旧版MySQL的伪窗口语法
性能陷阱:ORDER BY字段没索引会很慢
窗口函数依赖排序,若ORDER BY字段无索引,大数据量下可能触发临时文件排序,IO飙升。
- 检查执行计划,确认
ORDER BY列是否走了索引(特别是复合排序如ORDER BY dept_id, created_at,需要对应联合索引) - 避免在
LAG里用函数排序,比如ORDER BY DATE(created_at)会失索引,改用生成列或预计算字段 - 分区表场景下,若
PARTITION BY和ORDER BY能对齐分区键,性能提升明显
真正麻烦的是多级嵌套排序需求——比如既要按用户分组,又要在组内按时间倒序取“上一笔正向交易”,这时候LAG得配合FILTER或额外标记字段,不能光靠调参数解决。

















