LAG()本身不计算增长率,需用当前值减去LAG()取值再除以LAG()取值才能得到环比或同比;必须按时间严格排序、处理NULL和除零,并补全缺失月份以确保同比准确。

LAG() 本身不直接算增长率,得配合当前值做除法
LAG() 只是取上一行的值,比如上月销售额、去年同期值。要算环比(比上期)或同比(比去年同期),必须用当前行的值减去 LAG() 返回的值,再除以 LAG() 的值。漏掉这步除法,就只是差值,不是“率”。
常见错误是写成:LAG(sales) OVER (ORDER BY month) 就停了——这连百分比的影子都没有。
- 环比:需按时间升序排列,
LAG(sales, 1)取前1期(如上月) - 同比:需确保数据按年+月对齐,常用
LAG(sales, 12)(月度数据),但前提是时间字段已规整为连续月序列(如2023-01,2023-02…),不能是乱序日期 - 注意 NULL:首行无“上期”,
LAG()返回 NULL,直接参与除法会得 NULL;建议用NULLIF()避免除零,再配合COALESCE()补 0 或空字符串
月度环比增长率的典型写法(PostgreSQL / MySQL 8.0+ / SQL Server)
假设表 sales_monthly 有字段 ym(格式 '2023-01')、amount:
SELECT
ym,
amount,
ROUND(
(amount - LAG(amount, 1) OVER (ORDER BY ym)) * 100.0 /
NULLIF(LAG(amount, 1) OVER (ORDER BY ym), 0),
2
) AS mom_pct
FROM sales_monthly;关键点:
-
ORDER BY ym必须严格按时间升序,否则LAG()拿错行 - 乘
100.0是为避免整数除法截断(尤其在 PostgreSQL/SQL Server 中) -
NULLIF(..., 0)防止上期 amount 为 0 导致除零错误
同比计算必须对齐自然年周期,别只靠 OFFSET=12硬套
直接写 LAG(amount, 12) 看似简单,但极易出错——如果某个月缺失(如 2023-02 数据为空),那 2024-02 的 LAG(amount, 12) 会跳到 2023-01,而非真正的“去年同月”。
更稳妥的做法是先构造完整的时间维度,LEFT JOIN 补齐空月,再用 LAG():
WITH full_months AS (
SELECT DISTINCT ym FROM generate_series('2023-01', '2024-12', '1 month')::text AS ym
),
t AS (
SELECT m.ym, COALESCE(s.amount, 0) AS amount
FROM full_months m
LEFT JOIN sales_monthly s ON m.ym = s.ym
)
SELECT
ym,
amount,
ROUND(
(amount - LAG(amount, 12) OVER (ORDER BY ym)) * 100.0 /
NULLIF(LAG(amount, 12) OVER (ORDER BY ym), 0),
2
) AS yoy_pct
FROM t;真正容易被忽略的是:同比不是纯窗口函数问题,而是数据完整性问题。没补全月份,LAG(amount, 12) 就不可信。

















