LAG函数必须配合PARTITION BY分组和ORDER BY排序使用,如LAG(sales) OVER (PARTITION BY region ORDER BY month),否则会跨组混取数据;默认值处理需用COALESCE或NULLIF规避NULL和除零问题。

LAG函数怎么写才能正确取到上期分组数据
直接用 LAG(value) 不加分区会跨组混用,比如把B组的上一条(可能是A组末尾)当成B组的“上期”,结果全错。必须显式加上 PARTITION BY group_column,再按时间排序。
常见错误写法:LAG(sales) → 没分区、没排序,顺序随机;正确写法:LAG(sales) OVER (PARTITION BY region ORDER BY month)。
- 分区键(
PARTITION BY)必须和你的业务分组维度完全一致,比如按product_id算单品环比,就不能只写category -
ORDER BY字段必须能唯一确定时序,如果存在同月多条记录,得补上id或created_at防止窗口内排序不稳定 - PostgreSQL 和 SQL Server 支持
LAG(value, 1, 0)设置默认值,MySQL 8.0+ 才支持第三个参数,旧版得用COALESCE(LAG(...), 0)
计算环比增长率时除零和NULL怎么处理
上期值为 0 或 NULL 时,(cur - prev) / prev 会报错或返回 NULL,但业务上往往需要明确标识“不可算”或“新增”。不能靠外围 WHERE prev IS NOT NULL AND prev != 0 过滤,否则会丢掉首期数据。
- 统一用
NULLIF(prev, 0)替换分母,避免除零错误;再套一层COALESCE(..., NULL)显式控制空值行为 - 更稳妥写法:
ROUND(COALESCE((cur - prev) / NULLIF(prev, 0), NULL), 4),保留4位小数,NULL 表示无环比(首期或上期为0) - 如果想标出“新增”,可加判断:
CASE WHEN prev IS NULL THEN 'new' ELSE CAST(ROUND(...) AS STRING) END
为什么按月聚合后环比还是不准
原始数据常含多日明细,直接对日粒度跑 LAG 再算环比,会导致“某月最后一天 vs 上月最后一天”,而非“整月 vs 上月整月”。必须先聚合,再在聚合结果上开窗。
- 错误流程:明细表 →
LAG(sales) OVER (...)→ 再SUM()→ 环比失真 - 正确流程:先
GROUP BY year_month, product汇总当月 sales → 再对汇总结果用LAG(sales) OVER (PARTITION BY product ORDER BY year_month) - 注意
year_month类型要是可排序的,推荐用CHAR(7)格式(如 '2024-05'),别用INT(202405 和 202412 排序错乱)
不同数据库对LAG的支持差异有哪些
MySQL 5.7 不支持窗口函数,硬要实现得用自连接或变量,极易出错;Oracle 和 PostgreSQL 对 LAG 语义一致,但 SQL Server 的 ORDER BY 必须包含唯一列,否则可能重复取值。
- MySQL 8.0+:支持完整语法,但
LAG(col, n, default)的n参数不能是变量或表达式,只能是常量 - Trino/Presto:
LAG默认不支持默认值参数,必须用COALESCE(LAG(...), 0) - ClickHouse:用
neighbor()模拟 LAG,但需确保排序后数据物理连续,否则跨 block 取值失败
实际写之前,先 SELECT version() 确认引擎能力,别在测试环境能跑、生产报错。

















