游戏玩法分析 III

可紊 提交于 2020-02-08 05:23:08

——用户变量,系统变量,Join,IF,累加和或前缀和

Table: Activity

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| player_id    | int     |
| device_id    | int     |
| event_date   | date    |
| games_played | int     |
+--------------+---------+

(player_id,event_date)是此表的主键。
这张表显示了某些游戏的玩家的活动情况。
每一行是一个玩家的记录,他在某一天使用某个设备注销之前登录并玩了很多游戏(可能是 0 )。

编写一个 SQL 查询,同时报告每组玩家和日期,以及玩家到目前为止玩了多少游戏。也就是说,在此日期之前玩家所玩的游戏总数。详细情况请查看示例。

查询结果格式如下所示:

Activity table:

+-----------+-----------+------------+--------------+
| player_id | device_id | event_date | games_played |
+-----------+-----------+------------+--------------+
| 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            |
+-----------+-----------+------------+--------------+

Result table:

+-----------+------------+---------------------+
| player_id | event_date | games_played_so_far |
+-----------+------------+---------------------+
| 1         | 2016-03-01 | 5                   |
| 1         | 2016-05-02 | 11                  |
| 1         | 2017-06-25 | 12                  |
| 3         | 2016-03-02 | 0                   |
| 3         | 2018-07-03 | 5                   |
+-----------+------------+---------------------+

对于 ID 为 1 的玩家,2016-05-02 共玩了 5+6=11 个游戏,2017-06-25 共玩了 5+6+1=12 个游戏。
对于 ID 为 3 的玩家,2018-07-03 共玩了 0+5=5 个游戏。
请注意,对于每个玩家,我们只关心玩家的登录日期。

审题:计算每次登陆后的累计完了多少个游戏,将games_played改为累计数字。

思考:应该是一个求和问题,

解题:

方法一:

SELECT C.player_id,C.event_date,C.games_played_so_far
FROM (
SELECT 
	A.player_id,
	A.event_date,
@sum_cnt:=
		if(A.player_id = @pre_id AND A.event_date != @pre_date,
			@sum_cnt + A.games_played,
			A.games_played 
		)
		AS `games_played_so_far`,
@pre_id:=A.player_id AS `player_ids`,
@pre_date:=A.event_date AS `event_dates`
 
FROM 
activity AS A,(SELECT @pre_id:=NULL,@pre_date:=NULL,@sum_cnt:=0) AS B
order BY A.player_id,A.event_date
) AS C

自己写

select C.id,C.date,C.add From(
selcet A.id,A.date ,
@add := if(A.id = @id and A.date != @date,@add + A.add,A.add),
@id = A.id,
@date = A.date, FROM activity AS A,
(select @id := null, @date:= null,@add := 0)AS B
 
) AS C;

解题过程:

首先先按照id和日期排序。

定义用户变量:pre_id:上一行的player_id,pre_date: 上一行的event_date,sum_cnt:每个人games_played前缀和。

(select @pre_id:=Null,@pre_date:=Null,@sum_cnt:=0) As B

累计的计算逻辑:id相同,日期不同,就需要加上。如果并不符合就是本身次数就是次数的和:

if (当前行的player_id = pre_id and 当前行的event_date != pre_date){
    sum_cnt = sum_cnt + 当前行的games_played
}else{
    sum_cnt = games_played
}

转换为sql:

SELECT 
	A.player_id,
	A.event_date,
##如果条件成立执行+,条件不成立结果就是和。
@sum_cnt:= IF(A.player_id = @pre_id AND A.event_date != @pre_date,
			@sum_cnt + A.games_played,
			A.games_played 
		) AS `games_played_so_far`,
##给变量赋值
@pre_id:=A.player_id AS `player_ids`,
@pre_date:=A.event_date AS `event_dates`
FROM 
activity AS A,(
SELECT @pre_id:= NULL,@pre_date:= NULL,@sum_cnt:=0) AS B
ORDER BY A.player_id,A.event_date

但由于用户变量的限制,多出了两个字段player_ids,event_dates。

再投一次影,去掉多出的字段,即可得出第一种解法。

方法2:将当前日期和之前的玩过游戏的数量加起来。

同一个,在日期A当天和之前,用表自连接,group by,找出这些行。也是这类累加和或前缀和问题的通用解法:

SELECT *
FROM Activity AS A JOIN Activity AS B ON (A.player_id = B.player_id AND A.event_date <= B.event_date)

id相等,日期不同。

在加上排序和组内求和就是结果:

SELECT B.player_id,B.event_date,SUM(A.games_played) AS `games_played_so_far`
FROM Activity AS A JOIN Activity AS B 
ON (A.player_id = B.player_id AND A.event_date <= B.event_date)
GROUP BY B.player_id,B.event_date 

自己写

select B.id ,B.date, SUM(A.add) from Activity AS A  JOIN AS B ON (A.id = B.id AND A.date <= B.date) GROUP BY B.id, B.date;

知识点:

MySql用户变量:基于会话变量实现的, 可以暂存值, 并传递给同一连接里的下一条sql使用的变量.当客户端连接退出时,变量会被释放,用户变量:以"@“开始,形式为”@变量名",用户变量跟mysql客户端是绑定的,设置的变量,只对当前用户使用的客户端生效。也叫会话变量。

MySql用户变量赋值:如果使用没有初始化的变量,其值是NULL。使用set赋值时,使用的是“=”或者":=",使用select赋值时必须使用的是“:="。

MySql的IF():类似于Java的三目运算。

Mysql系统变量:以"@@“开始,形式为”@@变量名"。本题未涉及。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!