1hard + 2 mid,难度还行,当做练手。
1. 力扣1097:游戏玩法分析5
1.1 题目:
表:Activity
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| player_id | int |
| device_id | int |
| event_date | date |
| games_played | int |
+--------------+---------+
(player_id,event_date)是此表的主键(具有唯一值的列的组合)
这张表显示了某些游戏的玩家的活动情况
每一行表示一个玩家的记录,在某一天使用某个设备注销之前,登录并玩了很多游戏(可能是 0)
玩家的 安装日期 定义为该玩家的第一个登录日。
我们将日期 x 的 第一天留存率 定义为:假定安装日期为 X
的玩家的数量为 N
,其中在 X
之后的一天重新登录的玩家数量为 M
,M/N
就是第一天留存率,四舍五入到小数点后两位。
编写解决方案,报告所有安装日期、当天安装游戏的玩家数量和玩家的 第一天留存率。
以 任意顺序 返回结果表。
结果格式如下所示。
示例 1:
输入:
Activity 表:
+-----------+-----------+------------+--------------+
| player_id | device_id | event_date | games_played |
+-----------+-----------+------------+--------------+
| 1 | 2 | 2016-03-01 | 5 |
| 1 | 2 | 2016-03-02 | 6 |
| 2 | 3 | 2017-06-25 | 1 |
| 3 | 1 | 2016-03-01 | 0 |
| 3 | 4 | 2016-07-03 | 5 |
+-----------+-----------+------------+--------------+
输出:
+------------+----------+----------------+
| install_dt | installs | Day1_retention |
+------------+----------+----------------+
| 2016-03-01 | 2 | 0.50 |
| 2017-06-25 | 1 | 0.00 |
+------------+----------+----------------+
解释:
玩家 1 和 3 在 2016-03-01 安装了游戏,但只有玩家 1 在 2016-03-02 重新登录,所以 2016-03-01 的第一天留存率是 1/2=0.50
玩家 2 在 2017-06-25 安装了游戏,但在 2017-06-26 没有重新登录,因此 2017-06-25 的第一天留存率为 0/1=0.00
1.2 思路:
看到第一天条件反射就是窗口函数,然后判断是用rank(),dense_rank(), row_number()。
1.3 题解:
sql
-- 第一天=>排名第一=>窗口函数=>row_number
with tep1 as (
select player_id , event_date , row_number() over (partition by player_id order by event_date) ranks
from Activity
), tep2 as (
-- 查询到所有第一个登陆日的玩家
select *
from tep1
where ranks = 1
)
-- 然后以日期分组,installs即是该天第一个登陆日的玩家总数
select event_date install_dt, count(*) installs,
round(
(
-- 下面的子查询的意思是:
-- 该第一天的下一天且这个玩家在第一天出现过,并且ranks排第二,说明是第二天重新登录的玩家
-- where的三个条件才能限定第二天重新登录的数量。
-- 然后除以第一天登录的玩家总数,并取两个小数
select count(*)
from tep1 t2
where datediff(t1.event_date, t2.event_date) = -1 and ranks = 2
and player_id in (
select player_id
from tep2 t3
where datediff(t3.event_date, t2.event_date) = -1 and ranks = 1
)
) / count(*), 2
) Day1_retention
from tep2 t1
group by event_date
-- 虽然题目并不要求排序,但排序后明显时间缩短,效率提高
-- 因为答案输出给的表是顺序的
order by event_date
2. 力扣1149:文章浏览2
2.1 题目:
表: Views
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| article_id | int |
| author_id | int |
| viewer_id | int |
| view_date | date |
+---------------+---------+
此表可能会存在重复行。
此表的每一行都表示某人在某天浏览了某位作者的某篇文章。
请注意,同一人的 author_id 和 viewer_id 是相同的。
编写解决方案来找出在同一天阅读至少两篇文章的人。
结果按照 id
升序排序。
结果的格式如下。
示例 1:
输入:
Views 表:
+------------+-----------+-----------+------------+
| article_id | author_id | viewer_id | view_date |
+------------+-----------+-----------+------------+
| 1 | 3 | 5 | 2019-08-01 |
| 3 | 4 | 5 | 2019-08-01 |
| 1 | 3 | 6 | 2019-08-02 |
| 2 | 7 | 7 | 2019-08-01 |
| 2 | 7 | 6 | 2019-08-02 |
| 4 | 7 | 1 | 2019-07-22 |
| 3 | 4 | 4 | 2019-07-21 |
| 3 | 4 | 4 | 2019-07-21 |
+------------+-----------+-----------+------------+
输出:
+------+
| id |
+------+
| 5 |
| 6 |
+------+
2.2 思路:
注意到为什么要使用两个distinct。
2.3 题解:
sql
-- 先在原表过滤同一天阅读几篇相同的文章的情况,所以要去重
with tep as (
select distinct article_id, author_id, viewer_id, view_date
from Views
)
-- 然后根据view_date, viewer_id分组
-- 为什么要去重:打个比方:人物A在19号这天阅读了两篇文章,又在20号这天
-- 阅读了两篇文章,所以会查询到两个相同的记录A,所以要去重。
select distinct viewer_id id
from tep
group by view_date, viewer_id
having count(*) >= 2
order by id
3. 力扣1070:产品销售分析3
3.1 题目:
销售表 Sales
:
+-------------+-------+
| Column Name | Type |
+-------------+-------+
| sale_id | int |
| product_id | int |
| year | int |
| quantity | int |
| price | int |
+-------------+-------+
(sale_id, year) 是这张表的主键(具有唯一值的列的组合)。
product_id 是产品表的外键(reference 列)。
这张表的每一行都表示:编号 product_id 的产品在某一年的销售额。
请注意,价格是按每单位计的。
产品表 Product
:
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| product_id | int |
| product_name | varchar |
+--------------+---------+
product_id 是这张表的主键(具有唯一值的列)。
这张表的每一行都标识:每个产品的 id 和 产品名称。
编写解决方案,选出每个售出过的产品 第一年 销售的 产品 id 、年份 、数量 和 价格。
结果表中的条目可以按 任意顺序 排列。
结果格式如下例所示:
示例 1:
输入:
Sales 表:
+---------+------------+------+----------+-------+
| sale_id | product_id | year | quantity | price |
+---------+------------+------+----------+-------+
| 1 | 100 | 2008 | 10 | 5000 |
| 2 | 100 | 2009 | 12 | 5000 |
| 7 | 200 | 2011 | 15 | 9000 |
+---------+------------+------+----------+-------+
Product 表:
+------------+--------------+
| product_id | product_name |
+------------+--------------+
| 100 | Nokia |
| 200 | Apple |
| 300 | Samsung |
+------------+--------------+
输出:
+------------+------------+----------+-------+
| product_id | first_year | quantity | price |
+------------+------------+----------+-------+
| 100 | 2008 | 10 | 5000 |
| 200 | 2011 | 15 | 9000 |
+------------+------------+----------+-------+
3.2 思路:
-- 第一年=> 排名第一 => 窗口函数 => dense_rank
3.3 题解:
sql
-- 第一年=> 排名第一 => 窗口函数 => dense_rank
-- 因为第一年可能有多条记录,所以用dense_rank
with tep as (
select product_id , year , quantity, price, dense_rank() over (partition by product_id order by year) ranks
from Sales
)
select product_id, year first_year, quantity, price
from tep
where ranks = 1