LEAD() 和 LAG() 的核心用途是访问当前行之前或之后的指定行数据。LAG() 向上取前一行(如上月),LEAD() 向下取后一行(如下月),均需配合 ORDER BY 确保排序稳定,常用于环比计算、趋势分析等场景。

LEAD() 和 LAG() 的核心用途是什么?
这两个函数属于窗口函数,专门用来访问当前行「之前或之后」的某一行数据,不需要自连接或子查询。LAG() 向上取(比如上个月),LEAD() 向下取(比如下个月)。它们默认按 ORDER BY 指定的顺序逐行计算,所以必须明确指定排序字段(通常是日期)。
常见错误现象:LAG(sales) 返回全是 NULL,或者数值错位——大概率是没写 ORDER BY,或者排序字段有重复值但没加唯一性兜底(比如同一天多条记录时,应补上 id 或 ROW_NUMBER())。
实操建议:
- 始终在
OVER()里写全ORDER BY date(假设日期字段叫date) - 如果
date不唯一,追加, id避免窗口排序不稳定 -
LAG(sales, 1)表示取前 1 行,省略第二个参数默认为 1 - 别直接用
LAG(sales)做除法——它可能为 0 或NULL,需配合COALESCE()或条件判断
怎么算月度销售额环比增长(百分比)?
环比 = (本月 - 上月)/ 上月 × 100%。关键在于用 LAG() 安全取出「上月销售额」,再做运算。
示例(PostgreSQL / MySQL 8.0+ / SQL Server):
SELECT
date,
sales,
LAG(sales) OVER (ORDER BY date) AS prev_month_sales,
ROUND(
(sales - LAG(sales) OVER (ORDER BY date)) * 100.0 / NULLIF(LAG(sales) OVER (ORDER BY date), 0),
2
) AS mom_growth_pct
FROM sales_data;说明与注意点:
-
NULLIF(LAG(...), 0)防止除零错误,比CASE WHEN ... = 0 THEN NULL ELSE ... END更简洁 - 乘以
100.0(带小数点)确保结果为浮点数,避免整数除法截断(如 SQLite 或旧版 MySQL 中5/10得0) - 第一行的
prev_month_sales必为NULL,对应环比也应为NULL,这是正常行为,不是 bug - 若数据按自然月存储但存在跨月缺失(比如 2 月没数据),
LAG()会跳到 1 月,导致“跳月环比”——这不是函数问题,而是数据本身不连续;需先补全月份(用生成序列 + LEFT JOIN)
想看下月预测值?用 LEAD() 替换就行
LEAD() 和 LAG() 接口完全一致,只是方向相反。比如分析「当前月相比下月少了多少」,或做简单趋势预估(谨慎使用,不替代模型)。
示例:
SELECT date, sales, LEAD(sales) OVER (ORDER BY date) AS next_month_sales, sales - LEAD(sales) OVER (ORDER BY date) AS diff_to_next FROM sales_data;
容易踩的坑:
-
LEAD(sales, 1)取的是下一行,但最后一行没有「下一行」,返回NULL—— 别误以为是数据丢了 - 不要在
WHERE中过滤掉LEAD()为NULL的行(比如写WHERE next_month_sales IS NOT NULL),这会丢掉最后一行原始数据,影响总数统计 - 若需对
LEAD()结果再聚合(如平均下月值),记得先用子查询或 CTE 提取,否则窗口函数和聚合混用会报错
性能和兼容性要注意什么?
窗口函数在主流现代数据库中都支持,但细节差异大。
关键事实:
- MySQL 5.7 及更早版本不支持窗口函数,必须升级到 8.0+
- SQLite 3.25+ 支持,但
ROUND(x, 2)在某些旧版本中精度异常,建议测试 - SQL Server 和 PostgreSQL 表现最稳定,
OVER(ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)这类高级用法也可靠 - 大数据量下,
ORDER BY字段必须有索引,否则排序开销巨大;日期字段建索引几乎是必须项 - 别在视图里嵌套多层窗口函数(比如用
LAG()的结果再套一层LAG()),可读性和优化器支持都不好,拆成 CTE 更清晰
实际业务中,环比计算看似简单,但日期对齐、空值防御、除零控制、数据连续性验证,每个环节都可能埋雷。尤其当报表要自动跑进 BI 工具时,一个没处理的 NULL 或除零错误,就会让整个指标变红。

















