【LeetCode高频SQL50题-基础版】打卡第8天:第41~45题

【LeetCode高频SQL50题-基础版】打卡第8天:第41~45题

⛅前言

  在这个博客专栏中,我将为大家提供关于 LeetCode 高频 SQL 题目的基础版解析。LeetCode 是一个非常受欢迎的编程练习平台,其中的 SQL 题目涵盖了各种常见的数据库操作和查询任务。对于计算机科班出身的同学来说,SQL 是一个基础而又重要的技能。不仅在面试过程中经常会遇到 SQL 相关的考题,而且在日常的开发工作中,掌握 SQL 的能力也是必备的。

  本专栏的目的是帮助读者掌握 LeetCode 上的高频 SQL 题目,并提供对每个题目的解析和解决方案。我们将重点关注那些经常出现在面试中的题目,并提供一个基础版的解法,让读者更好地理解问题的本质和解题思路。无论你是准备找工作还是提升自己的技能,在这个专栏中,你可以学习到很多关于 SQL 的实践经验和技巧,从而更加深入地理解数据库的操作和优化。

  我希望通过这个专栏的分享,能够帮助读者在 SQL 的领域里取得更好的成绩和进步。如果你对这个话题感兴趣,那么就跟随我一起,开始我们的 LeetCode 高频 SQL 之旅吧!

好友申请II

🔒题目

题目来源:602.好友申请II:谁有最多的好友

image-20231014144055564

🔑题解

  • 考察知识点子查询union all

分析:我的思路是先分别统计 requester_id 和 accepter_id 这两列 id 出现的次数,然后将这两个统计结果使用 union all 聚合起来,基于这张聚合的临时表作最终的统计

1)分别统计 requester_id 和 accepter_id,使用 union all 对结果进行一个合并

注意:这里一定要使用 union all,而不是 union,因为 union 会直接将查询的结果进行去重,按照题目的含义,这里是不需要进行去重的,两列 id 出现的次数都需要进行统计的

select requester_id id, count(*) num
from RequestAccepted
group by requester_id
union all
select accepter_id id, count(*) num
from RequestAccepted
group by accepter_id
| id | num |
| -- | --- |
| 1  | 2   |
| 2  | 1   |
| 3  | 1   |
| 2  | 1   |
| 3  | 2   |
| 4  | 1   |

2)基于上面的表进行一个最终的结果获取

这一部就相当简单, 可以直接对按照 id 进行一个分组,然后使用 sum 聚合函数统计每一个 id 出现的次数,最终在降序排序,limit截取第一个元素,即可筛选出最终的结果

select id, sum(num) num
from(
    select requester_id id, count(*) num
    from RequestAccepted
    group by requester_id
    union all
    select accepter_id id, count(*) num
    from RequestAccepted
    group by accepter_id
) t
group by id
order by num desc
limit 1;

2016年的投资

🔒题目

题目来源:585.2016年的投资

image-20231014150225342

🔑题解

  • 考察知识点roundsum子查询group byinhavingcount

分析:这一题题意还算十分清晰,我们只需要按照题目要求一步一步来即可,题目要求我们查询出满足下面两个条件的所有投保人的在2016年的总金额

  1. 在 2015 年的投保额 (tiv_2015) 至少跟一个其他投保人在 2015 年的投保额相同。
  2. 所在的城市必须与其他投保人都不同(也就是说 (lat, lon) 不能跟其他任何一个投保人完全相同)

我的思路是,先查询出满足第一个条件的所有 tiv_2015,然后插叙出所有满足第二个条件的 lat 和 lon,再将这两个条件进行取一个交集,最周在利用 sum + round 函数对筛选出的记录进行一个求和,最后就可以得到最终的答案了

1)查询出满足第一个条件的所有的 tiv_2015

select tiv_2015
from Insurance 
group by tiv_2015
having count(*) > 1
| tiv_2015 |
| -------- |
| 10       |

2)查询出满足第二个条件的所有的 lat 和 lon

这里可以巧妙的利用 group by进行两个字段的分组,可能平常我们都是使用一个字段进行分组,实际上 group by可以同时按照多个字段进行分组

select lat, lon
from Insurance
group by lat, lon
having count(*) = 1
| lat | lon |
| --- | --- |
| 10  | 10  |
| 40  | 40  |

3)利用 in 和 and 使用上面两个结果集进行交集,然后筛选出符合所有条件的记录,最终通过 round 和 sum 进行最终的计算

select round(sum(tiv_2016), 2) tiv_2016
from Insurance
where tiv_2015 in (
    select tiv_2015
    from Insurance 
    group by tiv_2015
    having count(*) > 1
) and (lat, lon) in (
    select lat, lon
    from Insurance
    group by lat, lon
    having count(*) = 1
);

部门工资前三高的所有员工

🔒题目

题目来源:185.部门工资前三高的所有员工

image-20231014153006689

🔑题解

  • 考察知识点dense_rank子查询自连接countdistinct

分析:这一题最开始我的第一反应就是使用窗口函数,因为这种分组排序使用窗口函数将十分的方便,具体的思路如下

  1. 确定使用哪一个窗口函数,这里可以明确使用 dense_rank 窗口函数(并列排序,不会跳过重复的序号 1、1、2)
  2. 剩下的就很好办的,我们只需要筛选出排名前三的即可

1)利用窗口函数对所有的记进行员工分组排序

select *, dense_rank() over(partition by d.name order by salary desc) ranking
from Department d left join Employee e on d.id = e.departmentId
| id | name  | id | name  | salary | departmentId | ranking |
| -- | ----- | -- | ----- | ------ | ------------ | ------- |
| 1  | IT    | 4  | Max   | 90000  | 1            | 1       |
| 1  | IT    | 6  | Randy | 85000  | 1            | 2       |
| 1  | IT    | 1  | Joe   | 85000  | 1            | 2       |
| 1  | IT    | 7  | Will  | 70000  | 1            | 3       |
| 1  | IT    | 5  | Janet | 69000  | 1            | 4       |
| 2  | Sales | 2  | Henry | 80000  | 2            | 1       |
| 2  | Sales | 3  | Sam   | 60000  | 2            | 2       |

2)筛选出排名前三的员工信息

select  Department, Employee, salary
from(
    select d.name Department, 
       e.name Employee,
       e.salary,
       dense_rank() over(partition by d.name order by salary desc) ranking
    from Department d left join Employee e on d.id = e.departmentId
) t
where ranking <= 3 and salary is not null

窗口函数虽然好用,但是MySQL的版本必须是8或8以上才能使用,所以我们还是有必要掌握使用不同函数进行操作

分析:我们进行一个自连接,然后统计出所有排名在前三的员工信息

select d.name Department, e1.name Employee, e1.salary
from Employee e1 join Department d on e1.DepartmentId = d.id 
where 3 > (
    select count(distinct e2.salary)
    from Employee e2
    where e2.salary > e1.salary and e1.DepartmentId = e2.DepartmentId
);

下面这个SQL是含义是查询出比当前员工(e1)薪资高的员工数量,因为比排名第一员工薪资高的员工数量为0,所以计数是从0开始,并不像先前窗口函数中排名是从1开始的,所以这里 3 是大于,不能取等号

    select count(distinct e2.salary)
    from Employee e2
    where e2.salary > e1.salary and e1.DepartmentId = e2.DepartmentId

PS:说实话这个SQL是我看官方题解是摘自官方题解,一开始看着是有点懵的,后面多看几遍才理解了,我个人任务使用窗口函数更易于理解,同时窗口函数提的SQL比这条SQL效率更高(窗口函数的SQL是90%左右,这条SQL是50%左右)

修复表中的名字

🔒题目

题目来源:1667.修复表中的名字

image-20231014170005644

🔑题解

  • 考察知识点substringupperlowerconcat

    • substring(column_name, start, length):这将从列的值中提取一个子字符串,从指定的起始位置开始,直到指定的长度。注意截取索引是从1开始的,不是0
    • upper(expression):这会将字符串表达式转换为大写。
    • lower(expression):这会将字符串表达式转换为小写。
    • concat(string1, string2, ...):这会将两个或多个字符串连接成一个字符串。

    PS:这里只是讲解这些函数大概的作用,关于这些函数的详细使用大家可以参考MySQL教程

分析:这一题其实说简单也简单,说难也难,因为只要你有了解相关操作字符的 函数 可以秒杀这一题,如果你并不了解相关的 函数 可能就毫无头绪,所以大家在做题的时候,不要去死磕题目,没做出来可以适当的直接看题解

select user_id, concat(upper(substring(name, 1, 1)), lower(substring(name, 2, length(name)-1))) name
from Users
order by user_id asc;

备注:substring(name, 2, length(name)-1)这个函数可以简写为substring(name, 2)

患某种疾病的患者

🔒题目

题目来源:1572.患某种疾病的患者

image-20231014171657619

🔑题解

  • 考察知识点like

分析:直接使用 like 就可以了,但是需要注意一些比较细节的地方,DIAB1不一定出现在第一个位置,可以是第二个单词的位置,但是不能使用%DIAB1%去过滤,需要使用% DIAB1%这个去过滤,因为它是单词首位

select *
from Patients
where conditions like 'DIAB1%' or conditions like '% DIAB1%';

这里再推荐一种更加简洁的写法,直接使用正则表达式,没想到正则表达式无处不在,在MySQL中也可以使用正则表达式,不得不说正则表达太强大了

select patient_id, patient_name, conditions
from Patients
where conditions REGEXP '\\bDIAB1.*';
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知识汲取者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值