玩家首次登录的设备:要整行就用窗口函数
LeetCode 512 · 分组取首行、ROW_NUMBER / RANK
面试怎么回答
要的是最早那一行的设备,所以不能只 GROUP BY。我会用 ROW_NUMBER() OVER (PARTITION BY player_id ORDER BY event_date) 取 rn = 1;或者先算每人的最早日期,再用 (player_id, 日期) 回表拿设备。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
同一张活动表,求每个玩家第一次登录时用的设备。
表结构
- Activity:player_id、device_id、event_date、games_played;(player_id, event_date) 为主键
思路
和上一题的区别是要「最早那一行里的设备」,不是单个聚合值。GROUP BY 后直接 SELECT device_id 拿到的不一定是最早那天的设备,所以按玩家分区、日期升序排名,取排名第一的行。也可以先求出每个玩家的最早日期,再回表关联拿设备。
参考解法
select player_id ,device_id
from (
select player_id ,event_date,device_id,
rank() over(partition by player_id order by event_date) rk
from Activity
) tmp
where rk = 1
另一种写法:先求最早日期再回表关联
SELECT a.player_id, a.device_id
FROM Activity a
JOIN (SELECT player_id, MIN(event_date) AS d FROM Activity GROUP BY player_id) f
ON a.player_id = f.player_id AND a.event_date = f.d
易错点
SELECT player_id, device_id, MIN(event_date) ... GROUP BY player_id在宽松模式下能跑,但 device_id 是任意一行的值,不是最早那天的。