512. 游戏玩法分析 II 🔒
难度简单
题目描述
Table: Activity
+--------------+---------+ | Column Name | Type | +--------------+---------+ | player_id | int | | device_id | int | | event_date | date | | games_played | int | +--------------+---------+ (player_id, event_date) 是这个表的两个主键(具有唯一值的列的组合) 这个表显示的是某些游戏玩家的游戏活动情况 每一行是在某天使用某个设备登出之前登录并玩多个游戏(可能为0)的玩家的记录
请编写解决方案,描述每一个玩家首次登陆的设备名称
返回结果格式如以下示例:
示例 1:
输入: Activity table: +-----------+-----------+------------+--------------+ | player_id | device_id | event_date | games_played | +-----------+-----------+------------+--------------+ | 1 | 2 | 2016-03-01 | 5 | | 1 | 2 | 2016-05-02 | 6 | | 2 | 3 | 2017-06-25 | 1 | | 3 | 1 | 2016-03-02 | 0 | | 3 | 4 | 2018-07-03 | 5 | +-----------+-----------+------------+--------------+ 输出: +-----------+-----------+ | player_id | device_id | +-----------+-----------+ | 1 | 2 | | 2 | 3 | | 3 | 1 | +-----------+-----------+
解法
方法一:子查询
思考
在得到每人首次登录日之后,还要取出当天的 device_id。若直接 GROUP BY 设备,无法保证设备与最小日期同行。
子查询先按玩家求出 MIN(event_date),外层用 (player_id, event_date) 配对把对应设备筛出。联合键保证取到的是首次登录那一行,而不是任意一行。
我们可以使用 GROUP BY 和 MIN 函数来找到每个玩家的第一次登录日期,然后使用联合键子查询来找到每个玩家的第一次登录设备。
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
方法二:窗口函数
思考
子查询需要一次聚合再回表匹配。窗口函数可以在原表上按玩家按日期编号,直接留下排名为 \(1\) 的行。
RANK() OVER (PARTITION BY player_id ORDER BY event_date) 把首次登录标成 \(1\),外层过滤即可。语义与方法一相同,少一次显式自连接。
我们可以使用窗口函数 rank(),它可以为每个玩家的每个登录日期分配一个排名,然后我们可以选择排名为 \(1\) 的行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |