LAG()需显式ORDER BY确保逻辑顺序,推荐拼主键防重复;首行差值应依业务定NULL或0,避免COALESCE掩盖语义;单趟扫描通常快于自连接,但无索引排序时性能相近;MySQL强制ORDER BY,PostgreSQL允许但不推荐。
LAG() 怎么写才能正确拿到上一行的值
直接用 LAG(column_name) 就能取上一行,但默认行为是按当前查询的 ORDER BY 排序后取前一行——没写 ORDER BY 会报错或结果不可靠。窗口函数不认物理行序,只认逻辑排序顺序。
常见错误是漏掉 ORDER BY,或者排序字段有重复值又没加唯一性兜底(比如时间戳相同、ID缺失),导致 LAG() 拿到的“上一行”实际是任意一条同序记录。
- 必须显式写
ORDER BY,例如ORDER BY created_at, id - 如果排序字段可能重复,建议拼上主键(如
id)确保顺序唯一 -
LAG()第二个参数可设偏移量,默认为1;第三个参数是缺省值,比如LAG(amount, 1, 0)表示首行无上一行时填0
计算差值时 NULL 怎么处理最稳妥
首行没有“上一行”,LAG() 返回 NULL,直接做减法会让整行结果变 NULL。别依赖 COALESCE() 简单兜底——它掩盖了边界语义:首行差值本就无定义,填 0 或 NULL 是业务选择,不是技术补丁。
- 明确业务规则:首行是否要显示为
0?还是留空? - 若需数值型结果且允许首行为
0,用COALESCE(LAG(val) OVER (ORDER BY ts), 0) - 若想保留语义清晰性,建议让首行保持
NULL,并在应用层判断渲染(比如前端显示 “—”) - 避免写成
val - COALESCE(LAG(val), 0):这会让首行算出val - 0,看似有数,实则逻辑错误
为什么比自连接快,以及什么情况下反而更慢
LAG() 是单趟扫描,执行计划里通常只出现一次表访问;而自连接(如 JOIN ... ON t1.id = t2.id + 1)强制数据库做关联操作,数据量大时容易触发临时表或文件排序。