You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
select
name, mail
from (
select
user_id
from (
select
user_id,
contest_id -
row_number() over(partition by user_id order by contest_id) diff
from (
select contest_id, gold_medal user_id from contests
union allselect contest_id, silver_medal user_id from contests
union allselect contest_id, bronze_medal user_id from contests
) temp1
) temp2 group by user_id, diff havingcount(diff) >=3unionselect
gold_medal user_id
from contests group by gold_medal havingcount(gold_medal) >=3
) temp3 join users using(user_id);
解析
临时表 temp1 输出 contest_id 和 user_id 字段。
将 gold_medal、silver_medal、bronze_medal 获奖者分别查出来,使用 union all 将它们连接起来
查询临时表 temp3 ,将它和 users 表连接,连接条件是 user_id,输出 name 和 mail
SQL:方法二
with temp as (
select contest_id, gold_medal user_id from contests
union allselect contest_id, silver_medal user_id from contests
union allselect contest_id, bronze_medal user_id from contests
)
select name, mail from (
select user_id from (
select
user_id,
if(@pre_user_id = user_id,
if(@pre_contest_id = contest_id -1, @rank:=@rank, @rank:=@rank +1),
@rank:=1) diff,
@pre_contest_id:=contest_id,
@pre_user_id:=user_id
from temp,(select @pre_contest_id:=null, @pre_user_id:=null, @rank:=1) init
order by user_id, contest_id
) temp1 group by user_id, diff havingcount(diff) >=3unionselect
gold_medal
from contests group by gold_medal havingcount(gold_medal) >=3
) temp2 join users using(user_id);
with temp as (
select contest_id, gold_medal user_id from contests
union allselect contest_id, silver_medal user_id from contests
union allselect contest_id, bronze_medal user_id from contests
)
select name, mail from (
select
distinct temp1.user_idfrom temp temp1, temp temp2, temp temp3
wheretemp1.user_id=temp2.user_idandtemp2.user_id=temp3.user_idandtemp1.contest_id+1=temp2.contest_idandtemp2.contest_id+1=temp3.contest_idunionselect
gold_medal
from contests group by gold_medal havingcount(gold_medal) >=3
) t join users using(user_id);
解析
首先创建一个临时表 temp,将 gold_medal、silver_medal、bronze_medal 获奖者分别查出来,使用 union all 将它们连接起来。
with temp as (
select contest_id, gold_medal user_id from contests
union allselect contest_id, silver_medal user_id from contests
union allselect contest_id, bronze_medal user_id from contests
)
select name, mail from (
select user_id from (
select
user_id,
contest_id,
lead(contest_id, 1) over(partition by user_id order by contest_id) second,
lead(contest_id, 2) over(partition by user_id order by contest_id) third
from temp
) temp1 where contest_id +1= second and contest_id +2= third
unionselect
gold_medal
from contests group by gold_medal havingcount(gold_medal) >=3
) t join users using(user_id);
题目
题目连接:寻找面试候选人
contest_id
是该contest
的主键。该表包含 LeetCode 竞赛的id
和该场比赛中金牌、银牌、铜牌的user_id
。可以保证,所有连续的比赛都有连续的id
,没有id
被跳过。user_id
是该user_id
的主键。该表包含用户信息。编写 SQL 语句来返回面试候选人的 姓名和 邮件.当用户满足以下两个要求中的任意一条,其成为面试候选人:
可以以任何顺序返回结果。
分析
需要查询出的用户是
三场或者更多比赛的金牌比较好查询只需要筛选出金牌数大于等于
3
的用户。主要的关键点在于如何查询连续三场比赛获得奖牌。
这里使用了四种方法去解题:
if
函数1 + 1 = 2 and 1 + 2 = 3
SQL:方法一
解析
temp1
输出contest_id
和user_id
字段。gold_medal
、silver_medal
、bronze_medal
获奖者分别查出来,使用union all
将它们连接起来temp2
输出user_id
和diff
字段row_number()
进行排序,然后用contest_id
减去序号,得到diff
,如果是连续的数diff
是相同的temp2
,按照user_id
和diff
进行分组,筛选出count(diff) >= 3
,连续三场及以上的比赛,diff
的数量是大于3
的temp3
,将第3
步和第4
步使用union
连接temp3
,将它和users
表连接,连接条件是user_id
,输出name
和mail
SQL:方法二
解析
思路和方法一一样,区别是这里使用变量代替
row_number
因为其他步骤和方法一一样,所以这里只讲变量部分
设置三个变量,
@pre_contest_id
,@pre_user_id
,@rank
@pre_contest_id
保存的是上一场比赛的id
,初始化为null
@pre_user_id
保存的是上一个用户的id
,初始化null
@rank
保存的是当前排名,初始化为1
以
user_id = 2
为例@pre_user_id = null
,代入@pre_user_id = user_id
得null = 2
为false
进入@rank:=1
,此时diff
为1
。if
语句结束后,@pre_contest_id = 190
,@pre_user_id = 2
@pre_user_id = 2
,代入@pre_user_id = user_id
得2 = 2
为true
,进入if(@pre_contest_id = contest_id - 1, @rank:=@rank, @rank:=@rank + 1)
,此时@pre_contest_id = 190
,代入@pre_contest_id = contest_id - 1
的190 = 191 - 1
为true
,进入@rank:=@rank
,代入得@rank = 1
,此时diff
为1
if
语句结束后,@pre_contest_id = 191
,@pre_user_id = 2
Tips
if(@pre_contest_id = contest_id - 1, @rank:=@rank, @rank:=@rank + 1)
是关键,通过这步,可以直接算出diff
,而需要先算出排名rank
,再用题号减去rank
得到diff
SQL:方法三
解析
temp
,将gold_medal
、silver_medal
、bronze_medal
获奖者分别查出来,使用union all
将它们连接起来。temp
表自连,连接三次,分别是temp1
、temp2
、temp3
,除了user_id
的基本连接条件,最重要的是temp1.contest_id + 1 = temp2.contest_id and temp2.contest_id + 1 = temp3.contest_id
,意思是:上一场比赛 + 1 = 当前这场比赛
,当前这场比赛 + 1 = 下一场比赛
temp2.contest_id
看成当前这场比赛,temp1.contest_id
是上一场比赛,temp3.contest_id
是下一场比赛2
步和第3
步使用union
连接起来作为临时表t
t
,将它和users
表连接,连接条件是user_id
,输出name
和mail
Tips
可以替换成
join
方法四
解析
方法四和方法三的思路是一样的,只有第
2
步不一样,所以只讲解第2
步,其他步骤参考方法三。使用窗口函数
lead()
,计算出第二场比赛的contest_id
和第三场比赛的contest_id
lead(contest_id, 1) ... second
,lead(contest_id, 2) ... third
,lead
带领或者领导的意思,当前行带领一行,带领两行contest_id + 1 = second and contest_id + 2 = third
也可以使用窗口函数
lag()
,计算出上一场比赛的contest_id
和上两场比赛的contest_id
lag(contest_id, 1) ... last
,lag(contest_id, 2) ... last_two
,lag
滞后或落后的意思,当前行滞后一行,滞后两行contest_id - 1 = last and contest_id - 2 = last_two
也可以同时使用
lag(contest_id, 1) ... last
和lead(contest_id, 1) ... second
contest_id - 1 = last and contest_id + 1 = second
The text was updated successfully, but these errors were encountered: