窗口函数在业务里怎么用?举三个真实场景
总结
| 函数 | 场景 | 一句话总结 |
|---|---|---|
| ROW_NUMBER | TopN取数 | 每组取前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不加窗口范围会出错——默认窗口只到当前行,不是整个分区。