同比和环比是数据分析中常用的趋势衡量指标,环比指相邻两个统计周期的数据对比,比如本月和上月对比;同比指相同统计周期不同年份的数据对比,比如今年本月和去年本月对比。使用SQL的LAG窗口函数可以轻松实现跨行取数,快速完成这两类指标的计算。

LAG函数基础语法
LAG函数是SQL中的窗口函数,作用是获取当前行之前指定偏移量的行的数据,基础语法如下:
-- LAG函数基础语法 LAG(字段名, 偏移量, 默认值) OVER (PARTITION BY 分组字段 ORDER BY 排序字段)
参数说明:
- 字段名:要获取的字段值,比如销售额、订单量等
- 偏移量:向前取第几行的数据,1表示前一行,2表示前两行,以此类推
- 默认值:如果前面没有对应行时返回的默认值,可选,不填则返回NULL
- PARTITION BY:可选,用于分组,每个分组内独立计算偏移
- ORDER BY:必填,指定分组内的排序规则,决定行的先后顺序
环比数据计算实操
环比需要取当前周期的上一个周期数据,偏移量设置为1即可,以下以月度销售额环比为例:
示例数据表结构
假设有一张sales_monthly表,存储每月的销售额数据,结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| month_id | INT | 月份标识,格式为YYYYMM,比如202301表示2023年1月 |
| sales_amount | DECIMAL | 当月销售额 |
环比计算SQL
计算每月的销售额环比增长率,需要先取上月的销售额,再计算差值和增长率:
SELECT
month_id,
sales_amount AS current_month_sales,
-- 取上月的销售额,没有上月数据时返回0
LAG(sales_amount, 1, 0) OVER (ORDER BY month_id) AS last_month_sales,
-- 计算环比增长率,避免除数为0
CASE
WHEN LAG(sales_amount, 1, 0) OVER (ORDER BY month_id) = 0 THEN NULL
ELSE ROUND(
(sales_amount - LAG(sales_amount, 1, 0) OVER (ORDER BY month_id))
/ LAG(sales_amount, 1, 0) OVER (ORDER BY month_id) * 100,
2
)
END AS mom_growth_rate
FROM sales_monthly
ORDER BY month_id;
同比数据计算实操
同比需要取上一年相同周期的数据,这里需要结合时间处理逻辑,先构造年份和月份字段,再按月份分组取上一年的数据。
同比计算SQL
同样基于sales_monthly表,计算每月的销售额同比增长率:
-- 先提取年份和月份字段,方便按月份分组取上年数据
WITH sales_with_ym AS (
SELECT
month_id,
-- 提取年份,比如202301提取为2023
FLOOR(month_id / 100) AS year,
-- 提取月份,比如202301提取为1
MOD(month_id, 100) AS month,
sales_amount
FROM sales_monthly
)
SELECT
month_id,
sales_amount AS current_month_sales,
-- 取上一年同月的销售额,没有数据时返回0
LAG(sales_amount, 1, 0) OVER (PARTITION BY month ORDER BY year) AS last_year_same_month_sales,
-- 计算同比增长率
CASE
WHEN LAG(sales_amount, 1, 0) OVER (PARTITION BY month ORDER BY year) = 0 THEN NULL
ELSE ROUND(
(sales_amount - LAG(sales_amount, 1, 0) OVER (PARTITION BY month ORDER BY year))
/ LAG(sales_amount, 1, 0) OVER (PARTITION BY month ORDER BY year) * 100,
2
)
END AS yoy_growth_rate
FROM sales_with_ym
ORDER BY month_id;
这里通过PARTITION BY month将相同月份的数据分到一组,再按年份排序,偏移量1就表示取上一年的同月数据,完美实现同比取值。
常见问题处理
数据缺失场景
如果某个月份的数据缺失,LAG函数会返回默认值或者NULL,可以在计算前先补全缺失的周期数据,避免结果出现断层。比如用日期维度表左关联销售表,确保所有周期都有记录。
多维度分组场景
如果需要按地区、品类等多个维度计算同比环比,只需要在PARTITION BY中加上对应的分组字段即可,比如PARTITION BY region, month ORDER BY year,就可以按地区分别计算每个月的同比数据。
注意:LAG函数是窗口函数,不是聚合函数,不需要和GROUP BY一起使用,直接在SELECT子句中调用即可,不同数据库对窗口函数的支持略有差异,使用前可以确认当前数据库的兼容性。