在业务数据分析中,经常需要计算不同分组下指标的环比增长率,比如各门店每月销售额的环比变化、各产品每周销量的环比波动等。环比增长率的核心是需要获取当前周期和上一个周期的数值,而SQL的LAG窗口函数可以很方便地实现上期数据的获取,再结合简单的数学计算就能得到最终结果。

LAG函数的基本用法
LAG函数是SQL中的窗口函数,作用是返回当前行之前指定偏移量的行的数据。它的基本语法如下:
-- LAG函数基础语法 LAG(列名, 偏移量, 默认值) OVER (PARTITION BY 分组列 ORDER BY 排序列) AS 别名
参数说明:
- 列名:需要获取的上期数据的列
- 偏移量:向前偏移的行数,计算环比时通常设置为1,表示获取上一行的数据
- 默认值:当没有上一行数据时返回的默认值,比如首行没有上期数据可以返回0或者NULL
- PARTITION BY:指定分组的列,保证LAG函数只在当前分组内查找上期数据
- ORDER BY:指定分组内的排序规则,通常是时间列,保证上期数据是时间顺序上的上一个周期
分组环比增长率的计算逻辑
环比增长率的计算公式为:(当前周期数值 - 上期周期数值) / 上期周期数值 * 100%。结合LAG函数后,整个计算流程分为三步:
- 按分组列对数据进行分区,保证每个分组内的计算相互独立
- 在每个分区内按时间列排序,使用LAG函数获取每个行的上期数值
- 用当前数值和上期数值按照公式计算环比增长率,处理除数为0的异常情况
完整代码示例
假设我们有一张门店销售表store_sales,表结构如下:
| 列名 | 类型 | 说明 |
|---|---|---|
| store_id | INT | 门店ID |
| sale_month | DATE | 销售月份 |
| sale_amount | DECIMAL | 当月销售额 |
现在需要计算每个门店每月销售额的环比增长率,完整的SQL查询语句如下:
SELECT
store_id,
sale_month,
sale_amount,
-- 获取同门店上一个月份的销售额,没有上期数据时返回NULL
LAG(sale_amount, 1) OVER (PARTITION BY store_id ORDER BY sale_month) AS last_month_amount,
-- 计算环比增长率,处理上期数据为0或NULL的情况
CASE
WHEN LAG(sale_amount, 1) OVER (PARTITION BY store_id ORDER BY sale_month) IS NULL THEN NULL
WHEN LAG(sale_amount, 1) OVER (PARTITION BY store_id ORDER BY sale_month) = 0 THEN NULL
ELSE ROUND(
(sale_amount - LAG(sale_amount, 1) OVER (PARTITION BY store_id ORDER BY sale_month))
/ LAG(sale_amount, 1) OVER (PARTITION BY store_id ORDER BY sale_month) * 100,
2
)
END AS month_on_month_growth_rate
FROM store_sales
ORDER BY store_id, sale_month;
注意事项
在实际使用过程中需要注意以下几点:
- PARTITION BY的分组列需要和业务需求的分组一致,比如要计算各产品的环比,就需要按产品ID分组
- ORDER BY的排序列必须是周期列,且周期列的类型要支持排序,比如日期类型、数值类型的周期编号
- 如果上期数据可能不存在或者为0,一定要做异常判断,避免出现计算错误或者除零报错
- 不同数据库对窗口函数的支持略有差异,LAG函数在MySQL 8.0+、PostgreSQL、SQL Server 2012+等主流数据库中都支持,低版本数据库可能需要用自连接的方式实现相同逻辑
如果需要在低版本数据库实现相同功能,可以通过自连接将当前表和上期数据表关联,关联条件为分组列相同且上期周期等于当前周期减1,再计算增长率,不过性能会比LAG函数差一些。