同比对比是数据分析里最常见的需求之一,核心是比较当前周期与上一年度同一周期的数值差异。传统写法常借助自连接,而使用窗口函数LAG可以直接获取前第N行数据,让同比计算变得简单清晰。

什么是LAG窗口函数
LAG是SQL标准中的窗口函数,它能在不减少行数的前提下,访问当前行之前的某一行数据。进行同比时,我们往往按月份排序,取前12行即为上一年同月。
基础语法
SELECT month, amount, LAG(amount, 12) OVER (ORDER BY month) AS last_year_same_month FROM sales_monthly;
上面代码中,LAG(amount, 12)表示取往前第12行的amount值,配合OVER (ORDER BY month)按月份排序,即可得到去年同月数据。
实战:计算销售额同比
假设有表sales_monthly,字段为month(年月)、region(地区)、amount(销售额)。我们需要按地区分别计算同比。
建表与示例数据
CREATE TABLE sales_monthly (
month DATE,
region VARCHAR(20),
amount NUMERIC
);
INSERT INTO sales_monthly VALUES
('2022-01-01', 'East', 100),
('2022-02-01', 'East', 120),
('2023-01-01', 'East', 150),
('2023-02-01', 'East', 110),
('2022-01-01', 'West', 90),
('2023-01-01', 'West', 130);
按地区做同比查询
SELECT
region,
month,
amount,
LAG(amount, 12) OVER (
PARTITION BY region
ORDER BY month
) AS last_year_amount,
ROUND(
(amount - LAG(amount, 12) OVER (
PARTITION BY region ORDER BY month
)) / LAG(amount, 12) OVER (
PARTITION BY region ORDER BY month
) * 100, 2
) AS yoy_percent
FROM sales_monthly
ORDER BY region, month;
这里用PARTITION BY region让LAG在每个地区内独立计算,避免不同地区数据错位。yoy_percent即为同比增幅百分比。
处理缺失同期数据
如果某地区去年同月无记录,LAG会返回NULL,此时同比无法计算。可用COALESCE兜底或过滤。
SELECT
region,
month,
amount,
COALESCE(
LAG(amount, 12) OVER (PARTITION BY region ORDER BY month),
0
) AS last_year_amount
FROM sales_monthly;
注意事项
- LAG的偏移量要根据实际周期粒度设定,月度同比用12,季度同比用4。
- 排序字段必须连续且唯一,否则会取错行。
- 在MySQL 8.0、PostgreSQL、SQL Server等主流库均支持LAG。
用LAG做同比,逻辑直观、性能稳定,比自连接更好维护。