LAG()不返回NULL的关键是显式指定ORDER BY且字段为真实日期类型;多维同比需PARTITION BY;同比计算应为sales-LAG(sales,12),而非LAG-LAG;分母须用NULLIF防除零;数据周期完整性决定结果可靠性。

LAG() 函数怎么写才不会返回 NULL?
直接用 LAG() 查上期值,结果大部分是 NULL——不是函数坏了,而是没按时间维度正确排序和分组。窗口函数不认“自然顺序”,必须显式指定 ORDER BY,且该字段得是真正可排序的日期/时间类型(比如 DATE 或 TIMESTAMP),不能是字符串格式的 “2024-01”。
- 错误写法:
LAG(sales) OVER ()—— 没ORDER BY,行为未定义,多数引擎返回NULL或随机值 - 正确写法:
LAG(sales) OVER (ORDER BY order_date),确保order_date是真实日期类型 - 多维度同比(如按城市+月份):必须加
PARTITION BY city, YEAR(order_date), MONTH(order_date),否则跨城市混算 - 如果源数据有重复日期,先聚合再开窗,否则
LAG()可能跳过实际业务周期
同比计算时,为什么 LAG(sales) - LAG(sales) 不等于同比变化?
常见误解:以为拉两个 LAG() 就能算差值。实际上,同比需要“本期值”减去“去年同期值”,不是两个滞后值相减。核心是:一个 LAG() 拉同期,另一个字段提供当期,再做运算。
- 错误逻辑:
LAG(sales) - LAG(sales, 2)—— 这是隔两期的环比差,不是同比 - 正确逻辑:
sales - LAG(sales, 12) OVER (ORDER BY DATE_TRUNC('month', order_date))(PostgreSQL)或sales - LAG(sales, 12) OVER (ORDER BY YEAR(order_date), MONTH(order_date))(MySQL 8.0+) - 注意:
LAG(sales, 12)的偏移量必须匹配你的周期单位。月度同比=12,周同比=52,季度同比=4;别硬套“12”而不看数据粒度 - 如果数据缺失某月(比如 2023-02 没记录),
LAG(sales, 12)会跳到更早的非空值,导致同比错位——得先补全时间序列或用LEFT JOIN对齐
不同数据库对 LAG() 的日期处理差异有哪些?
MySQL、PostgreSQL、SQL Server 都支持 LAG(),但日期对齐方式差异很大,直接影响同比结果是否可信。
- MySQL 8.0+:不支持
DATE_TRUNC(),需用STR_TO_DATE(CONCAT(YEAR(order_date), '-', LPAD(MONTH(order_date), 2, '0'), '-01'), '%Y-%m-%d')构造标准月首,再ORDER BY - PostgreSQL:直接用
DATE_TRUNC('month', order_date)最稳,避免因日部分不同导致排序错乱 - SQL Server:
LAG()支持,但ORDER BY若用CONVERT(CHAR(7), order_date, 120)截取年月,可能因隐式转换引发性能问题,建议建计算列索引 - 所有引擎中,
LAG()的默认NULL填充值不可靠,显式写LAG(sales, 12, 0)更可控(但注意 0 和真实零值的区别)
为什么加了 LAG 还是算不准同比率?
同比率 = (本期 - 同期) / 同期,分母为 0 或 NULL 时整个表达式崩掉。这不是语法错误,而是业务逻辑断点。
- 直接写
(sales - LAG(sales, 12)) / LAG(sales, 12):只要任意一个LAG()返回NULL或分母为 0,整列变NULL - 必须用
NULLIF()或CASE处理分母:ROUND((sales - prev_year_sales) * 100.0 / NULLIF(prev_year_sales, 0), 2) - 更安全的做法:先用子查询或 CTE 算出
prev_year_sales,再在外层过滤掉prev_year_sales IS NULL OR prev_year_sales = 0 - 注意浮点精度:除法用
100.0而非100,避免整数截断(尤其在 SQL Server 中)
最常被忽略的点:同比的前提是“可比周期”。如果原始数据里 2023 年只有 6 个月销售,而 2024 年已有 12 个月,直接拉 12 步 LAG() 会让 2024-07 到 2024-12 的同比全部失效——得先确认基准周期是否完整,而不是只盯 SQL 有没有报错。










