环比增长率是指本次统计周期数据与上一个统计周期数据的比值变化,在SQL中可以通过窗口函数LAG和LEAD快速获取相邻周期的数据,无需进行复杂的自连接操作,大幅提升查询性能。

LAG和LEAD函数基础语法
LAG和LEAD都属于SQL窗口函数的范畴,主要用于获取当前行相邻行的数据,二者的基础语法结构一致:
-- LAG函数:获取当前行之前第n行的数据 LAG(列名, 偏移量n, 默认值) OVER (PARTITION BY 分组列 ORDER BY 排序列) AS 别名 -- LEAD函数:获取当前行之后第n行的数据 LEAD(列名, 偏移量n, 默认值) OVER (PARTITION BY 分组列 ORDER BY 排序列) AS 别名
其中偏移量n默认为1,表示获取相邻的一行数据;默认值可选,当没有对应行时返回该默认值,若不设置则返回NULL。
环比增长率计算逻辑
环比增长率的通用计算公式为:
环比增长率 = (本期数值 - 上期数值) / 上期数值 * 100%
结合LAG和LEAD函数,我们可以灵活选择获取上期数值的方式:
- 使用LAG函数直接获取当前行的前一行数据作为上期数值,适合按时间正序排列的场景
- 使用LEAD函数获取当前行的后一行数据作为本期数值,适合按时间倒序排列的场景
经典写法模板
模板一:LAG函数实现正序排列下的环比计算
假设我们有销售数据表sales,包含字段sale_date(销售日期)、product_id(产品ID)、sale_amount(销售金额),需要计算每个产品每日销售金额的环比增长率:
SELECT
product_id,
sale_date,
sale_amount,
-- 获取上一个周期的销售金额,没有则取0
LAG(sale_amount, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date) AS last_sale_amount,
-- 计算环比增长率,处理除数为0的情况
CASE
WHEN LAG(sale_amount, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date) = 0 THEN NULL
ELSE ROUND(
(sale_amount - LAG(sale_amount, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date))
/ LAG(sale_amount, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date) * 100,
2
)
END AS mom_growth_rate
FROM sales
ORDER BY product_id, sale_date;
模板二:LEAD函数实现倒序排列下的环比计算
如果数据是按时间倒序排列的,即最新的数据排在前面,可以使用LEAD函数获取下一行(更早的周期)的数据作为上期数值:
SELECT
product_id,
sale_date,
sale_amount,
-- 获取下一个周期(更早日期)的销售金额
LEAD(sale_amount, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date DESC) AS last_sale_amount,
CASE
WHEN LEAD(sale_amount, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date DESC) = 0 THEN NULL
ELSE ROUND(
(sale_amount - LEAD(sale_amount, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date DESC))
/ LEAD(sale_amount, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date DESC) * 100,
2
)
END AS mom_growth_rate
FROM sales
ORDER BY product_id, sale_date DESC;
注意事项
- PARTITION BY子句用于按指定字段分组,比如按产品ID分组后,每个产品的环比计算相互独立,不会互相干扰
- ORDER BY子句的排序规则需要和实际业务周期顺序一致,否则获取的上期数据会不符合预期
- 不同数据库对窗口函数的支持略有差异,MySQL 8.0+、PostgreSQL、SQL Server、Oracle均支持LAG和LEAD函数,低版本MySQL需要升级后使用
- 计算增长率时建议处理除数为0的场景,避免出现除以NULL导致的计算结果异常