首页/数据/SQL 速查/LAG 取上一行值
聚合与窗口函数54 条

LAG 取上一行值

取当前行之前第 N 行的值:环比、差值、会话切分等时序计算的基础;首行没有前值时返回默认值(可指定)。

SQL 速查数据更新于 2026-10-13

LAG 是什么

LAG 取当前行之前第 N 行的值,是环比、差值、时间间隔计算的基础。它有两个默认行为:偏移量默认为 1 行,找不到前值时返回 NULL,两者都可以显式指定。它是窗口函数,必须带 OVER 子句,且计算发生在 WHERE 与 GROUP BY 之后。

基本信息

语法LAG(expr [, offset [, default]]) OVER (ORDER BY …)
偏移量省略时为 1;写 2 表示往前数两行
默认值省略时首行返回 NULL,可显式指定为 0 之类
分区常配合 PARTITION BY 做组内环比
配对函数LEAD 取下一行,方向相反,参数一致
计算时机窗口函数在 WHERE / GROUP BY 之后执行,WHERE 里不能引用其结果

环比与差值

环比与差值
SELECT dt,
       amount,
       LAG(amount, 1) OVER (ORDER BY dt)          AS prev_amount,  -- 上一行金额
       amount - LAG(amount, 1) OVER (ORDER BY dt) AS diff,         -- 差额
       ROUND(100.0 * (amount - LAG(amount, 1) OVER (ORDER BY dt))
             / NULLIF(LAG(amount, 1) OVER (ORDER BY dt), 0), 2)    AS pct
FROM daily_sales
ORDER BY dt;   -- 首行三列均为 NULL:没有前值可比

组内环比与默认值

组内环比与默认值
SELECT store_id, month, revenue,
       LAG(revenue, 1, 0) OVER (PARTITION BY store_id ORDER BY month) AS prev_rev
FROM store_monthly
WHERE month >= '2024-01-01'
ORDER BY store_id, month;   -- 指定默认值 0:每个门店的首月不再返回 NULL

参数与行为

要点说明注意事项
offset往前第 N 行超出行范围按“没有前值”处理
default无前值时的返回值不指定时为 NULL
PARTITION BY在每个分组内独立计算漏写会让不同对象互相比较
ORDER BY决定“上一行”是谁排序键重复时前一行不确定
与 WHERE 关系先过滤再开窗还是先开窗再过滤,结果不同需要保留全量口径时包一层子查询

典型使用场景

  • 环比同比:本期与上期金额相减、相除
  • 相邻差值:库存变化、里程增量、传感器读数跳变
  • 会话切分:用与上一条的时间间隔判断是否属于同一会话
  • 排序后做条件判断,例如首次达到某个阈值的时点
  • 在结果里直接给出对比列,省去 BI 层再做自连接
  • 配合 LEAD 同时输出前后值,用于序列类数据的平滑判断
LAG 与 LEAD 是一对搭档:一个往前取、一个往后取,都严格依赖 ORDER BY。要拿“上一行”必须先有确定排序,否则结果每次执行都可能不同。
排序键有重复值或日期有缺口时,“上一行”不等于“上一个周期”。报表级环比要先补全日期序列,或在排序键后补主键作为次级排序,保证顺序确定。

易错点

  • 首行差值为 NULL:报表直接展示会出现空白或取值报错,用默认参数或在外层过滤处理
  • 漏写 PARTITION BY:不同门店、不同品类之间互相做环比,结果完全错误
  • 日期有缺口时直接 LAG:取到的是上一条记录而不是上一个周期,需要先补全日期序列
  • 在 WHERE 里引用 LAG 结果:窗口函数在 WHERE 之后计算,会直接报错,要包一层子查询或 CTE

数据来源与参考

  • MySQL 8.0 Reference Manual · LAG
  • PostgreSQL Documentation · Window Functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌