#该题目来源于力扣:
一,题目要求:
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
的元组,所以在外查询的时候不会出现数据公用的情况。
这就是必须使用联合查询的原因——避免数据共用的情况