订阅更新

窗口函数在业务里怎么用?举三个真实场景

Hive手册 第 15 题 约 5 分钟读完

本文目录
  1. 总结
  2. 场景一:LAG/LEAD算广告花费的同比环比
  3. 场景二:SUM OVER算月度累计花费曲线
  4. 场景三:FIRST\VALUE找用户首次触达渠道(归因分析)
  5. 面试加分:主动说出窗口范围的三种写法

总结

函数场景一句话总结
ROW_NUMBERTopN取数每组取前N条
LAG / LEAD同比环比和前/后N行对比
SUM OVER累计/移动平均截止当前行的汇总
FIRST / LAST_VALUE首末次归因每组的第一条/最后一条

面试的时候能举出多个场景,说明你不是死记语法,而是真正在业务中用过。能主动提到LAST_VALUE的窗口范围坑,绝对加分。

第11-15篇完结。下一辑继续聊表生命周期管理、埋点治理、作业调度设计、云迁移、项目经验表达等实战话题。

你们用窗口函数解决过最巧妙的场景是什么?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

窗口函数是SQL面试的核心,也是日常工作中最常用的高级功能。但很多人只会用ROW_NUMBER做TopN。其实窗口函数的威力远不止于此。今天用我在广告数据分析中的三个真实场景来展示。

场景一:LAG/LEAD算广告花费的同比环比

运营经常问:“今天的花费比昨天多了多少?比上周同期呢?”用LAG一行搞定:

SELECT
  dt,
  channel,
  cost,
  LAG(cost, 1) OVER (PARTITION BY channel ORDER BY dt) AS yesterday_cost,
  LAG(cost, 7) OVER (PARTITION BY channel ORDER BY dt) AS last_week_cost,
  ROUND(cost - LAG(cost, 1) OVER (PARTITION BY channel ORDER BY dt), 2)
    AS day_on_day_diff,
  ROUND((cost - LAG(cost, 7) OVER (PARTITION BY channel ORDER BY dt))
    / LAG(cost, 7) OVER (PARTITION BY channel ORDER BY dt) * 100, 1)
    AS week_on_week_pct
FROM ads_channel_cost
WHERE dt >= '2025-03-01' AND dt <= '2025-03-15';

LAG(cost, 1)取前1行(昨天),LAG(cost, 7)取前7行(上周同期)。这个写法比用自关联简洁很多。

类似地,LEAD取后几行。比如“用户从注册到首次付费花了几天”就可以用LEAD来算。

场景二:SUM OVER算月度累计花费曲线

运营想看“这个月每天的累计花费趋势”,判断预算消耗速度。用SUM OVER + 窗口范围:

SELECT
  dt,
  channel,
  cost,
  SUM(cost) OVER (
    PARTITION BY channel
    ORDER BY dt
    ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  ) AS running_total
FROM ads_channel_cost
WHERE dt >= '2025-03-01' AND dt < '2025-04-01';

ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW表示“从第一行到当前行”。这样每一行都显示截止当天的累计花费。

如果要算“近七天移动平均”,把窗口改成ROWS BETWEEN 6 PRECEDING AND CURRENT ROW就行。

场景三:FIRST_VALUE找用户首次触达渠道(归因分析)

广告归因分析中,经常需要知道用户“第一次是通过哪个渠道进来的”(first-touch attribution)。用FIRST_VALUE一行搞定:

SELECT
  user_id,
  event_time,
  channel,
  FIRST_VALUE(channel) OVER (
    PARTITION BY user_id
    ORDER BY event_time
  ) AS first_touch_channel,
  LAST_VALUE(channel) OVER (
    PARTITION BY user_id
    ORDER BY event_time
    ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
  ) AS last_touch_channel
FROM dwd_user_event
WHERE event_type = 'app_open';

注意LAST_VALUE必须加窗口范围ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING,否则默认窗口只到当前行,结果是错的。这个坑我踩过,排查了半天才发现。

面试加分:主动说出窗口范围的三种写法

ROWS BETWEEN: 按物理行数。ROWS BETWEEN 3 PRECEDING AND CURRENT ROW = 当前行和前3行。

RANGE BETWEEN: 按值范围。RANGE BETWEEN 7 PRECEDING AND CURRENT ROW = 值在当前值-7到当前值之间的所有行。

默认行为: 如果不指定窗口范围,默认是RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。这就是为什么LAST_VALUE不加窗口范围会出错——默认窗口只到当前行,不是整个分区。

刷题进度保存在当前浏览器