lag/lead必须搭配order by,否则语法报错;需用partition by隔离逻辑分组,排序字段须加唯一兜底(如id)防重复;首行/末行默认返回null,可用第三参数设默认值或coalesce处理。

LAG/LEAD 必须搭配 ORDER BY,否则直接报错
不写 OVER 子句里的 ORDER BY,数据库会立刻抛出错误:Window function requires an OVER clause with ORDER BY。这不是配置问题,而是语法强制要求——没有排序就没有“前后”概念。
常见误操作:只写 OVER(PARTITION BY category),漏掉 ORDER BY;或用模糊字段如 created_at 排序但没加唯一兜底。
-
LAG(revenue) OVER (PARTITION BY product ORDER BY created_at)→ 危险!多个订单同秒创建时,LAG可能拉错行 - 正确写法:
LAG(revenue) OVER (PARTITION BY product ORDER BY created_at, id)→ 用id消除歧义 - 如果排序字段天然唯一(如主键、自增 ID),单用它就够了:
ORDER BY id
默认值不填就是 NULL,第一行/最后一行必然出现 NULL
这是最常被忽略的细节:第一行调用 LAG()、最后一行调用 LEAD() 时,根本不存在对应行,函数不会“循环取值”,而是返回 NULL(除非你显式指定第三个参数)。
例如计算日环比:revenue - LAG(revenue) OVER (ORDER BY sale_date),首日结果为 NULL,后续计算可能因 NULL 传导导致整列变 NULL。
- 填默认值更安全:
LAG(revenue, 1, 0)→ 没前一日就当 0 - 用
COALESCE也可:COALESCE(LAG(revenue) OVER (...), 0) - 注意:默认值类型需和目标列一致,比如
LAG(price)不能写LAG(price, 1, 'N/A')
PARTITION BY 不是可选装饰,而是逻辑隔离的关键
没加 PARTITION BY,整个结果集当一个组算——跨产品、跨用户、跨时间线混在一起,LAG 可能把 A 用户最后一条记录和 B 用户第一条连起来。
典型场景:查每个用户的上一笔订单金额,不是查全表上一笔。
- 错误:
LAG(order_amount) OVER (ORDER BY order_time)→ 所有用户混排,顺序错乱 - 正确:
LAG(order_amount) OVER (PARTITION BY user_id ORDER BY order_time)→ 每个用户独立算“上一笔” -
PARTITION BY字段必须出现在查询中(或 GROUP BY 中),否则某些数据库(如 PostgreSQL)会报错
偏移量 offset 不是“跳过几行”,而是“取第几行的值”
新手容易误解 LAG(amount, 2) 是“跳过前两行再取”,其实它是“取往前数第 2 行的 amount 值”,即当前行的上上行。
比如按日期排序的销售记录:
第1天 → LAG(amount, 2) 返回 NULL
第2天 → 仍返回 NULL(只有 1 行在它前面)
第3天 → 返回第1天的 amount
-
LAG(col, 1)= 上一行;LAG(col, 2)= 上上行;LEAD(col, 3)= 下下下行 - 偏移量支持变量(如子查询结果),但多数引擎不支持表达式,如
LAG(col, @n)在 MySQL 中可行,PostgreSQL 需用generate_series配合 - 偏移量为负数无意义,会报错或静默转为 1
实际用得多的其实是稳定排序 + 分组 + 默认值三者组合,单独漏掉任何一个都容易在上线后突然跑出错数据。尤其要注意 ORDER BY 字段重复时的隐性错位——它不报错,但结果不可靠,得靠业务侧交叉验证。











