如何用 LAG()/LEAD() 计算环比增长率(同比/环比)

7次阅读

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

如何用 LAG()/LEAD() 计算环比增长率(同比/环比)

直接说结论:LAG() 和 LEAD() 本身不计算增长率,它们只取上下行的值;真正算环比增长率,必须用当前值减去 LAG() 值再除以 LAG() 值——而且要小心 NULL、除零和日期顺序问题。

确保 ORDER BY 正确且唯一

LAG() 和 LEAD() 依赖窗口排序,如果 ORDER BY 缺失或不唯一(比如多个记录同一天),结果会错乱甚至不可复现。

  • 必须按时间字段严格升序(环比)或按年月升序(同比),例如 ORDER BY sale_dateORDER 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 查询里混用,也别指望它自动处理重复时间戳。数据质量比函数技巧重要得多。

text=ZqhQzanResources