截至每天累计玩了多少局:窗口累计求和
LeetCode 534 · 累计求和、SUM OVER、自连接
面试怎么回答
用 SUM(games_played) OVER (PARTITION BY player_id ORDER BY event_date),默认窗口就是从第一行累计到当前行。我会提一句:排序键有重复时默认 RANGE 会把同值行一起累计,严格逐行累计要写 ROWS。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
对每个玩家的每个登录日期,计算到这一天为止(含当天)一共玩了多少局游戏。
表结构
- Activity:player_id、device_id、event_date、games_played;(player_id, event_date) 为主键
思路
累计值是窗口函数最典型的用法:按玩家分区、按日期排序做 SUM,默认窗口就是「从分区第一行到当前行」。不支持窗口函数时可以自连接:把同一玩家日期小于等于当前日期的行关联进来再求和,但数据量大时是 O(n²)。
参考解法
写法 1:窗口函数累计求和
select player_id,event_date ,
sum(games_played) over(partition by player_id order by event_date )games_played_so_far
from Activity
写法 2:自连接写法,适合不支持窗口函数的老版本
select
a1.player_id,
a1.event_date,
sum(a2.games_played) games_played_so_far
from Activity a1,Activity a2
where a1.player_id=a2.player_id and
a1.event_date>=a2.event_date
group by 1,2;
易错点
- ORDER BY 有重复值时,默认的 RANGE 窗口会把同值的行一起算进当前行;这里 (player_id, event_date) 唯一所以没问题,其他场景要显式写 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。