lag函数必须配合over(order by ...)才能正确取上一行值,否则结果不可控;首行返回null需用coalesce等显式处理;排序字段须具确定性,重复时应加二级排序。

LAG 函数的基本用法和必需的 ORDER BY
不加 ORDER BY 的 LAG() 没有意义,数据库无法确定“上一行”是谁。它不是按插入顺序,而是严格依赖 ORDER BY 子句定义的逻辑顺序。如果你看到差值混乱或全是 NULL,第一反应该检查排序字段是否唯一、是否覆盖了全部分组维度。
常见错误现象:LAG(value) OVER () 报错或返回不可预测结果;或差值全为 NULL(实际是因排序后首行无前驱)。
-
LAG()必须配合OVER (ORDER BY ...),且排序字段应具备业务意义(如时间戳、序号) - 若需按类别分别计算差值(比如每个用户独立算),必须加上
PARTITION BY user_id - 默认取前 1 行,偏移量可显式写成
LAG(value, 1),但省略更简洁
计算差值时如何避免 NULL 干扰结果
LAG() 对第一行始终返回 NULL,直接做减法会把整行结果拖成 NULL。不能靠应用层过滤,得在 SQL 里处理。
使用场景:你想看每日销售额变化,但首日没有“昨日销售额”,这时差值应为空或 0,而不是让整列变 NULL。
- 用
COALESCE(LAG(value), value)把首行的前值替换成自身,实现“首行差值为 0” - 更合理的是
value - COALESCE(LAG(value), 0),但要注意业务含义:0 是否代表“无前值” - 若差值仅对非首行有效,建议显式过滤:
WHERE LAG(value) IS NOT NULL(注意:WHERE 不能直接引用窗口函数,需套一层子查询或 CTE)
不同数据库对 LAG 的参数支持差异
PostgreSQL 和 SQL Server 支持三参数 LAG(value, offset, default),而 MySQL 8.0+ 和 Oracle 也支持,但 SQLite 目前(3.39+)仍不支持 default 参数。
性能影响:default 值不改变执行计划,只是简化表达式;但若用子查询模拟默认值,可能引发额外计算开销。
- PostgreSQL 示例:
LAG(sales, 1, 0) OVER (ORDER BY dt)— 首行差值 =sales - 0 - SQLite 用户必须写:
sales - COALESCE(LAG(sales) OVER (ORDER BY dt), 0) - offset 大于实际行数时,一律返回
default或NULL,不会报错
真实例子:按日期计算温度日变化量
假设表 weather 有 record_date DATE 和 temp_c NUMERIC,要得到“比前一天升高/降低多少度”:
SELECT record_date, temp_c, temp_c - COALESCE(LAG(temp_c) OVER (ORDER BY record_date), temp_c) AS delta_c FROM weather;
这里用 COALESCE(LAG(...), temp_c) 是为了让首日差值为 0(即 temp_c - temp_c),而非 NULL。如果业务要求首日留空,就改用 COALESCE(LAG(...), NULL) —— 但其实没必要,因为 LAG() 本来就是 NULL。
容易被忽略的一点:record_date 若有重复,ORDER BY record_date 无法保证稳定排序,差值可能每次执行都不一样。务必加一个唯一辅助字段,比如 ORDER BY record_date, id。











