lag是窗口函数,用于获取当前行向上偏移指定行数的值;必须配合含order by的over子句使用,参数依次为列名、偏移行数(默认1)、越界默认值(默认null),支持partition by分组计算。

LAG函数的基本用法和参数含义
LAG 是窗口函数,用来获取当前行向上偏移指定行数的值。它必须配合 OVER 子句使用,否则会报错 Window function 'LAG' requires an OVER clause。最简形式是 LAG(column_name),默认取上一行(OFFSET = 1),当没有上一行时返回 NULL。
-
LAG(column_name, offset, default_value)三个参数:要取值的列、偏移行数(正整数)、无数据时的默认值(可选) -
OVER中必须有ORDER BY,否则结果不可预期;是否加PARTITION BY取决于是否要分组独立计算 - 不支持在
WHERE或GROUP BY中直接使用LAG,得先用子查询或 CTE 包一层
常见错误:ORDER BY 写错或漏掉
没写 ORDER BY 会导致逻辑混乱,比如按时间查“上一笔订单”,但表本身无序,LAG 就可能拿错行。MySQL 8.0+、PostgreSQL、SQL Server 都要求显式排序。
- 错误写法:
SELECT LAG(amount) OVER () FROM orders→ 结果随机,不可靠 - 正确写法:
SELECT LAG(amount) OVER (ORDER BY created_at) FROM orders - 多字段排序更稳妥:
OVER (ORDER BY created_at, id),避免时间相同导致顺序不确定 - 如果业务需要按用户分组查“每个用户的上一笔订单”,就得加
PARTITION BY user_id
实际场景:计算环比变化(如销售额较上月增长多少)
典型需求是对比当前行和前一行的数值差异。这时不能只依赖 LAG 返回值,还要注意空值处理和数据类型。
- 示例:查每月销售额及环比增长率
SELECT month, sales, LAG(sales) OVER (ORDER BY month) AS prev_sales, ROUND((sales - LAG(sales) OVER (ORDER BY month)) / NULLIF(LAG(sales) OVER (ORDER BY month), 0), 4) AS mom_growth FROM monthly_report;
-
NULLIF防止除零错误;首行prev_sales是NULL,所以mom_growth也是NULL - 别重复写三遍
LAG(sales) OVER (ORDER BY month),复杂逻辑建议用 CTE 提前算好
性能与兼容性注意点
LAG 在大数据量下会触发全窗口扫描,尤其 PARTITION BY 分区多、每组数据大时,性能下降明显。
- PostgreSQL 和 SQL Server 对
LAG优化较好;MySQL 8.0 起支持,但旧版本不识别,会报错FUNCTION xxx does not exist - Hive/Spark SQL 支持,但偏移量不能是列引用(即
LAG(col, n)中n必须是常量) - 如果只是查“上一条记录”且数据量小,又不想用窗口函数,可以考虑自连接或子查询,但逻辑更绕、易出错
LAG 看似简单,但真正用稳的关键在于:排序必须明确、空值必须处理、分区边界要理清。很多人卡在第一行结果为 NULL 就以为函数失效,其实那是设计使然。











