astak16 / blog-mysql

LeetCode 数据库刷题

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

15 游戏玩法分析 III

astak16 opened this issue · comments

题目

查询每组玩家和日期,以及玩家到目前位置玩了多少游戏,也就是说,再此日期之前玩家所玩的游戏总数。

create table activity (
	player_id int,
	device_id int,
	event_date date,
	games_played int
);

insert into activity values
(1, 2, '2016-03-01', 5),
(1, 2, '2016-05-02', 6),
(1, 3, '2017-06-25', 1),
(3, 1, '2016-03-02', 0),
(3, 4, '2018-07-03', 5);

SQL:方法一

select player_id, event_date,
	sum(
		case
			when @pre_player_id = player_id then @n:=@n+games_played
			when @pre_player_id:= player_id then @n:=games_played
		end
	) as games_played_so_far
from (
	select * from activity order by player_id, event_date
) temp, (select @pre_player_id:=null, @n:=0) init
group by player_id, event_date;

解析

因为最终的结果是计算每个用户在某天玩游戏的次数,所以需要按照 player_idevent_date 分组。

因为 order by 执行的顺序在 sum 函数后面执行,所以这里需要先对 player_idevent_date 先进行排序。

具体实现:

  • activity 按照 player_idevent_date 升序排序,命名为 temp 临时表
  • 将临时表 temp 按照 player_idevent_date 进行分组
  • 使用 case ... when ... then ...end 语句对分组后的 tempgames_played 进行输出,并用 sum 求和

SQL:方法二

select
	player_id,
	event_date,
	sum(games_played)
	 over(partition by player_id order by event_date) as games_played_so_far
from activity;

解析

sum 函数后面可以使用 over 对其按照 player_id 分组,并按照 event_date 排序。

SQL:方法三

select a.player_id, a.event_date, sum(b.games_played) as games_played_so_far
from activity a join activity b
on a.player_id = b.player_id where a.event_date >= b.event_date
group by a.player_id, a.event_date;

解析

  • 将表 activity 自连,连接条件 a.player_id = b.player_id 筛选出 a.event_date >= b.event_date
  • 按照 a 表的 player_ida.event_date 进行分组
  • 在求和的时候,使用的是 b.games_played
    • 因为筛选条件是 a.event_date >= b.event_date 也就是说在 a.event_date >= b.event_date 的数据中, a.games_played 都是一样的,是不对的。