LAG()和LEAD()仅取值,不计算增长率;环比需用当前值减LAG值再除以LAG值,并处理NULL、除零及排序唯一性;同比须补全时间维度或严格校验日期偏移。

直接说结论:LAG() 和 LEAD() 本身不计算增长率,它们只取上下行的值;真正算环比增长率,必须用当前值减去 LAG() 值再除以 LAG() 值——而且要小心 NULL、除零和日期顺序问题。
确保 ORDER BY 正确且唯一
LAG() 和 LEAD() 依赖窗口排序,如果 ORDER BY 缺失或不唯一(比如多个记录同一天),结果会错乱甚至不可复现。
- 必须按时间字段严格升序(环比)或按年月升序(同比),例如
ORDER BY sale_date或ORDER BY YEAR(sale_date), MONTH(sale_date) - 若存在多笔同日数据,需追加唯一列(如
id)避免不确定性:ORDER BY sale_date, id - MySQL 8.0+、PostgreSQL、SQL Server 都支持,但 SQLite 目前不支持窗口函数
写环比增长率:LAG() + 安全除法
常见错误是直接写 (amount - LAG(amount)) / LAG(amount),一遇到首行 LAG() 返回 NULL 或 LAG(amount)=0 就崩。
- 用
COALESCE(LAG(amount), 0)拦截 NULL,但更推荐用CASE WHEN显式控制逻辑 - 必须判断分母是否为 0,否则 PostgreSQL 报
division by zero,MySQL 可能返回 NULL 或警告 - 示例(标准写法):
SELECT sale_date, amount, CASE WHEN LAG(amount) OVER (ORDER BY sale_date) = 0 THEN NULL ELSE ROUND((amount - LAG(amount) OVER (ORDER BY sale_date)) * 100.0 / LAG(amount) OVER (ORDER BY sale_date), 2) END AS mom_pct FROM sales;
同比怎么搞?LEAD()/LAG() 不适合直接做年同比
LAG(amount, 12) 看起来像同比,但前提是数据严格按月、无缺失——现实中月份可能缺位(比如 2023-02 数据没上报),这时 LAG(amount, 12) 会取到 2022-02 前一条(可能是 2022-01),结果完全错误。
- 真正健壮的同比应先补全时间维度(用 generate_series 或日历表),再 JOIN 对齐同期
- 若坚持用 LAG(),至少加校验:
LAG(sale_date, 12) OVER (...) = sale_date - INTERVAL '12 months',不满足则置 NULL - 注意时区和月末处理:2023-01-31 的同比是 2022-01-31,但 2023-02-30 不存在,数据库行为各不相同(PostgreSQL 截断,MySQL 可能报错)
最易被忽略的一点:LAG()/LEAD() 是窗口函数,不是聚合函数——别在 GROUP BY 查询里混用,也别指望它自动处理重复时间戳。数据质量比函数技巧重要得多。










