LAG函数必须配合OVER(ORDER BY)使用,否则结果不可靠;默认取上一行,支持指定偏移量和默认值;首行返回NULL需用COALESCE兜底;不可在WHERE中直接引用,须用子查询或CTE。

LAG 函数必须配合 ORDER BY 使用,否则结果不可靠
LAG 不是简单取上一条记录,而是按指定排序逻辑“往前看一行”。没写 ORDER BY 的窗口定义,数据库可能按物理存储顺序返回,不同执行、不同版本结果都可能变。
常见错误现象:LAG(value) 返回 NULL 或乱序值,尤其在多行数据中看似“偶尔对、偶尔错”——本质是缺少确定性排序。
- 必须在
OVER (ORDER BY ...)中明确排序字段,例如时间戳、自增ID - 若需按分组分别取上一行,加
PARTITION BY,比如每个用户独立计算:OVER (PARTITION BY user_id ORDER BY created_at) - 避免用无索引字段排序(如
name),会拖慢性能;时间类字段通常有索引,优先选
默认返回 NULL,但可以指定替代值防崩
当当前行是分区第一行(或整个结果集首行)时,LAG() 没有“上一行”,默认返回 NULL。如果业务逻辑不能接受 NULL(比如做减法、比较),直接报错或结果异常。
使用场景:计算环比增长、判断状态变化、填充缺失基准值。
- 用第三个参数指定默认值,例如:
LAG(sales, 1, 0) OVER (ORDER BY month)—— 没上一行时返回0 - 注意类型匹配:默认值类型要和目标列一致,否则可能隐式转换失败(如
LAG(created_at, 1, '1970-01-01')) - 别用
COALESCE(LAG(...), 0)替代默认值参数,多一层函数调用且无法规避首次 NULL
offset 参数不是“跳过几行”,而是“往前取第几行”
LAG(value, offset) 的 offset 是偏移量,1 表示上一行,2 表示上两行,以此类推。有人误以为 offset=0 是当前行——实际无效,会报错或被忽略(行为因数据库而异)。
性能影响:增大 offset 不增加计算开销,窗口框架仍是完整扫描,但可读性下降,易引发逻辑误解。
-
LAG(value, 1)和LAG(value)等价,1可省略 -
LAG(value, 3)取的是当前行向上数第三行的value,不是跳过三行再取 - 避免大 offset(如 100+),除非业务真需要,否则难维护且容易和业务语义脱节
MySQL 8.0+ 和 PostgreSQL 支持完整语法,旧版 MySQL 需绕行
MySQL 5.7 及更早版本不支持窗口函数,强行用 LAG 会报错 FUNCTION xxx.LAG does not exist。PostgreSQL 8.4+、SQL Server 2012+、Oracle 10g+ 均支持。
兼容方案(仅限 MySQL 5.7):
- 用自连接 + 排序字段差值模拟,例如
JOIN t t2 ON t.id = t2.id + 1(要求 ID 连续) - 用变量赋值:
@prev := @curr+@curr := value,但需严格控制执行顺序,ORDER BY 必须生效且无并发干扰 - 最稳妥是升级到 MySQL 8.0+,窗口函数已稳定,语法统一
跨数据库移植时,LAG 本身兼容性好,但默认值参数(第三个参数)在部分旧版 PostgreSQL 中不支持,需查文档确认。










