订阅更新

截至每天累计玩了多少局:窗口累计求和

SQL 实战 123 题 · 第 16 题 中等 约 2 分钟读完

LeetCode 534 · 累计求和、SUM OVER、自连接

本文目录
  1. 面试怎么回答
  2. 题意
  3. 表结构
  4. 思路
  5. 参考解法
  6. 易错点

面试怎么回答

用 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。
刷题进度保存在当前浏览器