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 题解:
-- 第一天=>排名第一=>窗口函数=>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 题解:
-- 先在原表过滤同一天阅读几篇相同的文章的情况,所以要去重
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 题解:
-- 第一年=> 排名第一 => 窗口函数 => 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