订阅更新

玩家首次登录的设备:要整行就用窗口函数

SQL 实战 123 题 · 第 15 题 简单 约 2 分钟读完

LeetCode 512 · 分组取首行、ROW_NUMBER / RANK

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

面试怎么回答

要的是最早那一行的设备,所以不能只 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 是任意一行的值,不是最早那天的。
刷题进度保存在当前浏览器