#38 指标体系 中等

同比和环比怎么定义?用 SQL 怎么算、口径上有哪些坑?

同比环比LAG周期对齐口径

🎯 考察意图

这题考的不是背「环比看上一期、同比看去年」,而是候选人能不能先把窗口钉死再算比率:比的是哪个指标、对齐的是完整周期还是残缺周期、分母为 0 怎么办。只报一个百分比、说不清 MTD 不能对上月全月、闰年怎么对齐,这题就浅了。

📐 回答框架

  1. 先钉契约:同一个指标、同一粒度、同一成功态;环比是相邻周期,同比是去年同期。
  2. 再钉窗口:完整自然周/月/年才能直接比;残缺周期(MTD、周至今)必须对齐到同等天数或去年同日。
  3. 计算:先按周期聚合,再用 LAG 或自连接取基期,输出相对变化和绝对变化。
  4. 解读:看基数、工作日、大促;比率和差额一起报,禁止只丢一个涨跌幅。

💬 参考答案(口述版)

一句话:环比拿「上一期完整窗口」当镜子,同比拿「去年同一个窗口」当镜子;先对齐天数和口径,再相除。残缺的本月至今,不能去除以完整的上个月。

定义我面试会先讲清楚,避免和业务各说各的:
- 环比:相邻等长周期相比。日环比是今天 vs 昨天,周环比是本周 vs 上周,月环比是本月 vs 上月。
- 同比:跨年对齐。10 月同比是今年 10 月 vs 去年 10 月;日同比是今天 vs 去年同一天(或去年同一周几,事先说死)。
- 公式:(本期 - 基期) / 基期。基期为 0 或接近 0 时不要硬除,改报绝对增量,或标「基期过小、比率无意义」。

落地不要在明细行上直接 LAG 日期再除,先把指标聚到周期粒度:

-- 月 GMV:先按月折好,再取上月、去年同月
WITH monthly AS (
  SELECT
    date_trunc('month', dt)::date AS month_start,
    SUM(pay_amt) AS gmv
  FROM ads_pay_success
  GROUP BY 1
)
SELECT
  month_start,
  gmv,
  LAG(gmv, 1) OVER (ORDER BY month_start) AS mom_base,
  LAG(gmv, 12) OVER (ORDER BY month_start) AS yoy_base,
  gmv - LAG(gmv, 1) OVER (ORDER BY month_start) AS mom_delta,
  (gmv - LAG(gmv, 1) OVER (ORDER BY month_start))
    / NULLIF(LAG(gmv, 1) OVER (ORDER BY month_start), 0) AS mom_rate,
  (gmv - LAG(gmv, 12) OVER (ORDER BY month_start))
    / NULLIF(LAG(gmv, 12) OVER (ORDER BY month_start), 0) AS yoy_rate
FROM monthly;

LAG(..., 1) 是环比基期,LAG(..., 12) 是月粒度同比基期。日粒度同比用 LAG(..., 365) 会在闰年错位,更稳的是自连接 dt = 去年同一天 或 dt - INTERVAL '1 year'。

窗口没对齐,比率就是假的。我默认三条规矩:
1. 完整比完整:9 月全月 vs 8 月全月、vs 去年 9 月。
2. 残缺比对等残缺:10 月 1–10 日,环比应对 9 月 1–10 日(或上一个等长 10 天),同比应对去年 10 月 1–10 日,禁止对 9 月 30 天。
3. 工作日/大促要声明:周二对周一的日环比常被周末和活动打穿;双 11 的同比要同时报「含活动」和「剔除活动日」两套,或至少口头标注。

口述收尾:先说「环比相邻、同比去年同期」,再主动提 MTD 对齐和 NULLIF 防除零,最后报比率时带上基期绝对值。面试官要的是你会把镜子摆正,不是会背两个名词。

🔍 关键词

环比同比周期对齐LAG对等天数

💭 面试官可能的追问

追问 1:本月还没过完,老板要看「这个月比上个月怎么样」,你怎么回?

不能拿 MTD 去除以上个月全月,天数不同,跌是假跌。三条合法比法,选一条并写在标题上:① 本月 1 号到昨天 vs 上月同一号段(对等天数环比);② 本月 1 号到昨天 vs 去年同月同一号段(对等天数同比);③ 用日均 GMV 比,再乘当月剩余工作日做预测,预测要标明「按日均外推,不是实际」。看板标题写成「截至 10 日的对等天数环比」,不要写「月环比」。

追问 2:LAG 和自连接怎么选?闰年、2 月、周对齐怎么处理?

周期连续、粒度均匀(月、周)用 LAG 最干净。日同比、要「去年同一天」或「去年同一周几」用自连接更稳:a.dt = b.dt + INTERVAL '1 year' 在 2 月 29 日会丢行,需要约定:闰日同比并到 2 月 28 或 3 月 1,写进指标说明书。周同比不要拿「第 42 周」对「第 42 周」就完,ISO 周年和节日错位很常见,电商更常对「去年同一周几的最近一天」或「去年大促同活动窗」。对齐规则必须先于 SQL。

追问 3:环比涨 8%、同比跌 12%,你怎么讲给业务听?

先报基数:8% 是从 1000 万到 1080 万,还是从 10 万到 10.8 万,决策完全不同。再拆窗口:环比涨可能只是相对上月淡季回升,同比跌说明相对去年旺季在掉。接着切维度:新老客、渠道、类目、是否含大促。常见故事是「上月活动退潮后的环比修复」叠「去年同期有更强活动」。结论不要停在涨跌幅,要落到「相对谁、窗口是否可比、绝对值够不够大」。

⚠️ 常见踩坑

  • 用本月至今去除以上月全月,残缺周期直接当月环比
  • 日同比用 LAG 365 天,闰年或夏令时把日期对歪
  • 基期接近 0 仍硬除,从 1 单到 3 单报「涨 200%」
  • 只报百分比不报基期绝对值,也不断言工作日和大促

🧠 记忆锚点

环比比相邻,同比比去年同期;先对齐完整窗口再除,残缺周期只比对等天数。