最近只写mid题了。
1. 力扣 614:二级关注者
1.1 题目:
表:Follow
+-------------+---------+ | Column Name | Type | +-------------+---------+ | followee | varchar | | follower | varchar | +-------------+---------+ (followee, follower) 是该表的主键(具有唯一值的列的组合)。 该表的每一行表示关注者关注了社交网络上的被关注者。 不会有用户关注他们自己。
二级关注者 是指满足以下条件的用户:
- 关注至少一个用户,
- 被至少一个用户关注。
编写一个解决方案来报告 二级用户 及其关注者的数量。
返回按 follower
字典序排序 的结果表。
结果格式如下所示。
示例 1:
输入: Follow table: +----------+----------+ | followee | follower | +----------+----------+ | Alice | Bob | | Bob | Cena | | Bob | Donald | | Donald | Edward | +----------+----------+ 输出: +----------+-----+ | follower | num | +----------+-----+ | Bob | 2 | | Donald | 1 | +----------+-----+ 解释: 用户 Bob 有 2 个关注者。Bob 是二级关注者,因为他关注了 Alice,所以我们把他包括在结果表中。 用户 Donald 有 1 个关注者。Donald 是二级关注者,因为他关注了 Bob,所以我们把他包括在结果表中。 用户 Alice 有 1 个关注者。Alice 不是二级关注者,但是她不关注任何人,所以我们不把她包括在结果表中。
1.2 思路:
看注释。
1.3 题解:
-- 因为二级关注者被至少一个用户关注。
-- 所以其followee肯定在follower 出现过(即有其他人关注了该二级关注者)
with tep as (
select *
from Follow
where followee in (
select follower
from Follow
)
)
-- 然后分组计数
select followee follower, count(*) num
from tep
group by followee
order by follower
2. 力扣1355:活动参与者
2.1 题目:
表: Friends
+---------------+---------+ | Column Name | Type | +---------------+---------+ | id | int | | name | varchar | | activity | varchar | +---------------+---------+ id 是朋友的 id,并且在 SQL 中,是该表的主键 name 是朋友的名字 activity 是朋友参加的活动的名字
表: Activities
+---------------+---------+ | Column Name | Type | +---------------+---------+ | id | int | | name | varchar | +---------------+---------+ 在 SQL 中,id 是该表的主键 name 是活动的名字
找出那些既没有最多,也没有最少参与者的活动的名字。
Activities
表中的任意活动都有在 Friends
中参与过。
可以以 任何顺序 返回结果。
下面是返回结果格式的例子。
示例 1:
输入: Friends 表: +------+--------------+---------------+ | id | name | activity | +------+--------------+---------------+ | 1 | Jonathan D. | Eating | | 2 | Jade W. | Singing | | 3 | Victor J. | Singing | | 4 | Elvis Q. | Eating | | 5 | Daniel A. | Eating | | 6 | Bob B. | Horse Riding | +------+--------------+---------------+ Activities 表: +------+--------------+ | id | name | +------+--------------+ | 1 | Eating | | 2 | Singing | | 3 | Horse Riding | +------+--------------+ 输出: +--------------+ | activity | +--------------+ | Singing | +--------------+ 解释: Eating 活动有三个人参加, 是最多人参加的活动 (Jonathan D. , Elvis Q. and Daniel A.) Horse Riding 活动有一个人参加, 是最少人参加的活动 (Bob B.) Singing 活动有两个人参加 (Victor J. and Jade W.)
2.2 思路:
看注释。先得到排名,然后去掉排名第一和倒一。
2.3 题解:
with tep1 as (
-- 第一步:先分组计算每个活动的次数
select activity, count(*) cnt
from Friends
group by activity
), tep2 as (
-- 第二步:计算每个活动依据次数得到的排名
select activity, cnt, dense_rank() over (order by cnt) ranks
from tep1
), tep3 as (
-- 第三步:得到排名榜的第一名和最后一名的排名
select first_value(ranks) over (order by ranks rows between unbounded preceding and unbounded following) value
from tep2
union all
select last_value(ranks) over (order by ranks rows between unbounded preceding and unbounded following) value
from tep2
)
-- 然后在where中过滤掉排名最高和最低的即可。
select activity
from tep2
where ranks not in (select * from tep3)
3. 力扣1341:电影评分
3.1 题目:
表:Movies
+---------------+---------+ | Column Name | Type | +---------------+---------+ | movie_id | int | | title | varchar | +---------------+---------+ movie_id 是这个表的主键(具有唯一值的列)。 title 是电影的名字。
表:Users
+---------------+---------+ | Column Name | Type | +---------------+---------+ | user_id | int | | name | varchar | +---------------+---------+ user_id 是表的主键(具有唯一值的列)。 'name' 列具有唯一值。
表:MovieRating
+---------------+---------+ | Column Name | Type | +---------------+---------+ | movie_id | int | | user_id | int | | rating | int | | created_at | date | +---------------+---------+ (movie_id, user_id) 是这个表的主键(具有唯一值的列的组合)。 这个表包含用户在其评论中对电影的评分 rating 。 created_at 是用户的点评日期。
请你编写一个解决方案:
- 查找评论电影数量最多的用户名。如果出现平局,返回字典序较小的用户名。
- 查找在
February 2020
平均评分最高 的电影名称。如果出现平局,返回字典序较小的电影名称。
字典序 ,即按字母在字典中出现顺序对字符串排序,字典序较小则意味着排序靠前。
返回结果格式如下例所示。
示例 1:
输入: Movies 表: +-------------+--------------+ | movie_id | title | +-------------+--------------+ | 1 | Avengers | | 2 | Frozen 2 | | 3 | Joker | +-------------+--------------+ Users 表: +-------------+--------------+ | user_id | name | +-------------+--------------+ | 1 | Daniel | | 2 | Monica | | 3 | Maria | | 4 | James | +-------------+--------------+ MovieRating 表: +-------------+--------------+--------------+-------------+ | movie_id | user_id | rating | created_at | +-------------+--------------+--------------+-------------+ | 1 | 1 | 3 | 2020-01-12 | | 1 | 2 | 4 | 2020-02-11 | | 1 | 3 | 2 | 2020-02-12 | | 1 | 4 | 1 | 2020-01-01 | | 2 | 1 | 5 | 2020-02-17 | | 2 | 2 | 2 | 2020-02-01 | | 2 | 3 | 2 | 2020-03-01 | | 3 | 1 | 3 | 2020-02-22 | | 3 | 2 | 4 | 2020-02-25 | +-------------+--------------+--------------+-------------+ 输出: Result 表: +--------------+ | results | +--------------+ | Daniel | | Frozen 2 | +--------------+ 解释: Daniel 和 Monica 都点评了 3 部电影("Avengers", "Frozen 2" 和 "Joker") 但是 Daniel 字典序比较小。 Frozen 2 和 Joker 在 2 月的评分都是 3.5,但是 Frozen 2 的字典序比较小。
3.2 思路:
相当于将两个窗口函数排名的问题糅合了起来,然后最终输出union all。
3.3 题解:
with tep1 as (
-- 第一步: 得到每个用户名评论电影的个数
select u.user_id user_id, name, count(*) cnt
from Users u
join MovieRating m
on u.user_id = m.user_id
group by u.user_id
), tep2 as (
-- 第二步:得到每个用户名个数的排名
-- 最后where限制ranks即可得到第一名
select name, row_number() over (order by cnt desc, name) ranks
from tep1
), tep3 as (
-- 第一步: 得到每个电影的均分
select title, avg(rating) avg_rat
from MovieRating m1
join Movies m2
on m1.movie_id = m2.movie_id
and created_at >= '2020-02-01' and created_at < '2020-03-01'
group by title
), tep4 as (
-- 第二步:将每个电影的均分进行排名
-- 最后where限制ranks即可
select title, row_number() over (order by avg_rat desc, title) ranks
from tep3
)
-- 将两个输出union all
select name results
from tep2
where ranks = 1
union all
select title results
from tep4
where ranks = 1
4. 力扣1555:银行账户概要
4.1 题目:
用户表: Users
+--------------+---------+ | Column Name | Type | +--------------+---------+ | user_id | int | | user_name | varchar | | credit | int | +--------------+---------+ user_id 是这个表的主键(具有唯一值的列)。 表中的每一列包含每一个用户当前的额度信息。
交易表:Transactions
+---------------+---------+ | Column Name | Type | +---------------+---------+ | trans_id | int | | paid_by | int | | paid_to | int | | amount | int | | transacted_on | date | +---------------+---------+ trans_id 是这个表的主键(具有唯一值的列)。 表中的每一列包含银行的交易信息。 ID 为 paid_by 的用户给 ID 为 paid_to 的用户转账。
力扣银行 (LCB) 帮助程序员们完成虚拟支付。我们的银行在表 Transaction 中记录每条交易信息,我们要查询每个用户的当前余额,并检查他们是否已透支(当前额度小于 0)。
编写解决方案报告:
user_id
用户 IDuser_name
用户名credit
完成交易后的余额credit_limit_breached
检查是否透支 ("Yes" 或 "No")
以任意顺序返回结果表。
结果格式见如下所示。
示例 1:
输入: Users
表: +------------+--------------+-------------+ | user_id | user_name | credit | +------------+--------------+-------------+ | 1 | Moustafa | 100 | | 2 | Jonathan | 200 | | 3 | Winston | 10000 | | 4 | Luis | 800 | +------------+--------------+-------------+Transactions
表: +------------+------------+------------+----------+---------------+ | trans_id | paid_by | paid_to | amount | transacted_on | +------------+------------+------------+----------+---------------+ | 1 | 1 | 3 | 400 | 2020-08-01 | | 2 | 3 | 2 | 500 | 2020-08-02 | | 3 | 2 | 1 | 200 | 2020-08-03 | +------------+------------+------------+----------+---------------+ 输出: +------------+------------+------------+-----------------------+ |user_id
|user_name
|credit
|credit_limit_breached
| +------------+------------+------------+-----------------------+ | 1 | Moustafa | -100 | Yes | | 2 | Jonathan | 500 | No | | 3 | Winston | 9900 | No | | 4 | Luis | 800 | No | +------------+------------+------------+-----------------------+ Moustafa 在 "2020-08-01" 支付了 $400 并在 "2020-08-03" 收到了 $200 ,当前额度 (100 -400 +200) = -$100 Jonathan 在 "2020-08-02" 收到了 $500 并在 "2020-08-08" 支付了 $200 ,当前额度 (200 +500 -200) = $500 Winston 在 "2020-08-01" 收到了 $400 并在 "2020-08-03" 支付了 $500 ,当前额度 (10000 +400 -500) = $9900 Luis 未收到任何转账信息,额度 = $800
4.2 思路:
看注释。
4.3 题解:
-- ifNull函数是为了避免没有交易记录出现null的情况
with tep as (
select user_id, user_name,
credit - ifNull((select sum(amount) from Transactions where paid_by = user_id), 0)
+ ifNull((select sum(amount) from Transactions where paid_to = user_id), 0) credit
from Users
)
-- 增加字段判断是否透支
-- 为啥不将credit_limit_breached放在tep临时表中作为最后的一个字段
-- 因为如果其放在credit字段后
-- 其判断的是Users表中的credit,而不是其计算得到的字段credit
-- 因为计算得到的字段是将上面几行代码当成一张表的credit字段
select user_id, user_name, credit,
case when credit >= 0 then 'No'
else 'Yes'
end credit_limit_breached
from tep
5. 力扣2041:面试中被录取的候选人
5.1 题目:
表:Candidates
+--------------+----------+ | Column Name | Type | +--------------+----------+ | candidate_id | int | | name | varchar | | years_of_exp | int | | interview_id | int | +--------------+----------+ candidate_id 是这个表的主键(具有唯一值的列)。 该表的每一行都表示候选人的姓名、工作年限以及面试 ID 。
表:Rounds
+--------------+------+ | Column Name | Type | +--------------+------+ | interview_id | int | | round_id | int | | score | int | +--------------+------+ (interview_id, round_id)是本表的主键(具有唯一值的列的组合)。 本表的每一行都表示一轮面试的分数
编写解决方案,找出 至少有两年 工作经验、且面试分数之和 严格大于 15
的候选人的 ID 。
可以以 任何顺序 返回结果表。
查询结果的格式如下例所示。
示例 1:
输入: Candidates table: +--------------+---------+--------------+--------------+ | candidate_id | name | years_of_exp | interview_id | +--------------+---------+--------------+--------------+ | 11 | Atticus | 1 | 101 | | 9 | Ruben | 6 | 104 | | 6 | Aliza | 10 | 109 | | 8 | Alfredo | 0 | 107 | +--------------+---------+--------------+--------------+ Rounds table: +--------------+----------+-------+ | interview_id | round_id | score | +--------------+----------+-------+ | 109 | 3 | 4 | | 101 | 2 | 8 | | 109 | 4 | 1 | | 107 | 1 | 3 | | 104 | 3 | 6 | | 109 | 1 | 4 | | 104 | 4 | 7 | | 104 | 1 | 2 | | 109 | 2 | 1 | | 104 | 2 | 7 | | 107 | 2 | 3 | | 101 | 1 | 8 | +--------------+----------+-------+ 输出: +--------------+ | candidate_id | +--------------+ | 9 | +--------------+ 解释: - 候选人 11 :总分是 16 ,1 年工作经验。由于工作年限,不列入结果表。 - 候选人 9 :总分是 22 ,6 年工作经验。列入结果表。 - 候选人 6 :总分是 10 ,10 年工作经验。由于分数不足,不列入结果表。 - 候选人 8 :总分是 6 ,0 年工作经验。由于工作年限和分数,不列入结果表。
5.2 思路:
两个要求两个where过滤即可。
5.3 题解:
-- 第一步:过滤工作经验少于两年的人
with tep as (
select candidate_id, interview_id
from Candidates
where years_of_exp >= 2
), temp as (
-- 第二步:计算每个候选人的面试分数
select candidate_id, sum(score) sum_score
from tep t
join Rounds r
on t.interview_id = r.interview_id
group by candidate_id
)
-- 第三步:过滤面试分数和不足15的候选人
select candidate_id
from temp
where sum_score > 15