自学内容网 自学内容网

[每日一练]游戏玩法分析(为什么使用子查询而不是having字段,为什么必须使用联合查询)

#该题目来源于力扣:

512. 游戏玩法分析 II - 力扣(LeetCode)

一,题目要求:

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         |
+-----------+-----------+

二,思路流程:

这道题要求我们对是所有用户进行最小日期的查询,并且返回玩家的id和设备的id,所以我们的SELECT字段输出就是“player_id”和“device_id”,然后对player_id进行分组,最后利用having字段筛选出日期最小的条件,代码应该为:

# Write your MySQL query statement below
SELECT player_id,device_id
from Activity
group by player_id 
having min(event_date)

遗憾地说,这种方法是错误的。因为根据having字段的性质,它的作用是筛选分组聚合后的数据。而所谓的分组聚合后的数据就是select字段里的数据,having要想筛选它们,字段里就必须要包括这些数据,再进行条件筛选。这上面这段代码里,having只是筛选了日期,但是没有筛选select字段里的player_id和device_id,也就是聚合分组后的数据,所以上面的代码作废。

想查询出有最小日期的player_id和device_id,我们可以通过子查询在where的字段里进行求解:

select player_id, device_id
from activity
where (player_id,event_date) in 
(select player_id,min(event_date)
from activity
group by player_id)

三,题后思考

为什么在where字段不直接子查询event_date一个数据,而是联合查询player_id和event_date呢?如下所示:

select player_id, device_id
from activity
where event_date in 
(select min(event_date)
from activity
group by player_id)

这个代码是不可行的。

  • 在内部的子查询里,只查询event_date的最小值,它返回的也只有包含分组后的所有最小event_date元组的数据集,并不包括player_id和device_id的信息。
  • 外部查询从 activity 表中选择 player_id 和 device_id,然后检查 event_date 是否在子查询的结果中。也就是说,外部查询只会返回 event_date 在最小日期集合中的所有行。

结果会造成严重的BUG,简而言之就是,可能造成多个player_id同时使用一个最小日期的情况。而在思路流程种正确的代码,它的内内查询返回的是包括最小event_date 的player_id 的元组,所以在外查询的时候不会出现数据公用的情况。

这就是必须使用联合查询的原因——避免数据共用的情况


原文地址:https://blog.csdn.net/2302_77975940/article/details/143025208

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!