LeetCode——数据库

LeetCode数据库部分的一些刷题记录

前言

秋招季的事情暂时告一段落了,闲了这么久,是时候重新学起来了。之前把操作系统和计网简单复习了下,趁现在有点闲时间,继续补强下数据结构、算法等基础知识。
准备刷LeetCode边练边复习,先整点简单的——LeetCode的数据库篇。之前在牛客上也有一个数据库专题,做也做了二三十道,但是时间有点久了,就不写了。
本篇就只记录在LeetCode上数据库部分做题的笔记


刷题

题目都在LeetCode上:https://leetcode-cn.com/problemset/database/
SQL语言用的是mysql

175、组合两个表 简单

这题就是连接两张表,查表1的FirstName,LastName和表2的City,State信息,不过要注意的是这里的题目条件,要用外连接而不能内连接。所以直接写左连接查询语句。

1
2
3
4
5
6
7
8
select 
p.FirstName as FirstName,
p.LastName as LastName,
a.City as City,
a.State as State
from
Person as p left join Address as a
on p.PersonId = a.PersonId


176、第二高的薪水 简单

这题目的是查询第二高的薪水,如果不存在则返回null。
第二高的话,排序之后直接用limit 1,1就好了,关键是这个不存在返回null,不存在又分为表数据不够,比如表只有一行。或者另一种情况,薪水全部一样,则也不存在第二高的薪水,因此这题除了按薪水降序排序外,还需要筛掉薪水相同的记录。可以像下面这样写使用group by或者用distinct + order by

1
2
3
4
5
6
select 
Salary as SecondHighestSalary
from
Employee
group by Salary desc
limit 1,1

但是这样写的话,不存在第二高记录的话会返回空而不是null,因此还需小小改动下。最终代码如下

1
2
3
4
5
6
7
8
select (
select
Salary
from
Employee
group by Salary desc
limit 1,1
) as SecondHighestSalary


177、第N高的薪水 中等

这题跟上一题差不多,不过是他把第二换成了第N,包装进一个函数里面去。不过话说回来,我这sql语句还没写过函数呢···。不过应该也就增删查改那几样。

1
2
3
4
5
6
7
8
9
10
11
12
create function getNthHighestSalary(N int) returns int
begin
set N=N-1;
return (
select
Salary
from
Employee
group by Salary desc
limit N,1
);
end

这里注意的是第N高,limit写法是limit N-1,1,但是这样写要报语法错误,只能先用set把N赋值为N-1。


178、分数排名 中等

这题要把成绩按分数进行排名,分数降序排列倒是好办,但按照分数进行排名就有点绕了。之前在牛客上那个专题写过类似的题目,用到的是子查询,时间有点久了,有点忘了,看了看评论区老哥们的评论才绕出来。2333 T-T~

细心一点,把需求拆成子需求,分而治之 233~
这题要求输出两列,一列是分数降序排列Score,一列是分数排名(排名可并列)Rank。
分数排列查询语句
很简单,order by即可

1
select Score from Scores order by Score desc

排名查询语句
某个分数的排名等于有多少个大于等于它的分数的数量,用语句来写的话就是

1
2
select count(distinct Score) from Scores where Score >= s1.Score
# s1.Score是要进行排名的分数

综合一下,整个语句就是

1
2
3
4
5
6
7
8
9
10
11
12
13
select 
s1.Score as Score,
(
select
count(distinct Score)
from
Scores
where Score>=s1.Score
) as Rank
from
Scores as s1
order by
s1.Score desc


180、连续出现的数字 中等

找出表中连续出现3次以上的数字,这里注意是连续出现3次,如果只是出现次数大于3次的话,用count + group by 就好了,但是这里是连续出现,就意味着id必须要连续。
这题也是看评论看来的,看完醍醐灌顶,woc,原来这么简单啊,自己怎么想不到,枯了 T-T

连续出现次数大于3次,不必去数次数,利用连续这个点,3张表内连接,用值相等、Id连续条件进行限制,如果刚好出现次数等于3次的话,则该数在结果中出现一次,如果连续出现次数大于3次的话,该数会在结果里出现n-2(n>3)次,所以再加个distinct t1.Num限制。

1
2
3
4
5
6
7
8
9
10
11
select 
distinct t1.Num as ConsecutiveNums
from
Logs as t1,
Logs as t2,
Logs as t3
where
t1.Num = t2.Num and
t2.Num = t3.Num and
t2.Id = t1.Id+1 and
t3.Id = t2.Id+1


181、超过经理收入的员工 简单

这题有点牛客上内味了,查询收入超过员工所属经理的员工的姓名。
注意这里的条件,一是员工收入超过经理,二是该员工是在该经理手下。
先左连接一下,连接条件是t1.ManagerId=t2.Id,然后就好办了,一个where条件的事情

1
2
3
4
5
6
select 
t1.Name as Employee
from
Employee as t1 left join Employee as t2 on t1.ManagerId=t2.Id
where
t1.Salary > t2.Salary


182、查找重复的电子邮箱 简单

这题也太简单了吧,group by+having。

1
2
3
4
5
6
7
select 
Email
from
Person
group by
Email
having count(Email)>1


183、从不订购的客户 简单

这题也简单,客户表和订单表,找没有订单的客户名,直接用个not in美滋滋

1
2
3
4
5
6
7
8
9
10
11
select 
t1.Name as Customers
from
Customers as t1
where
t1.Id not in (
select
CustomerId
from
Orders
)


184、部门工资最高的员工 中等

这题本来以为挺容易的,两张表,员工表和部门表,本来以为两个表连接一下, 按部门group by + max就好了,但是写完之后发现好像差点意思,于是只能就地改改,代码改的非常丑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
select
t2.Department as Department,
t1.Name as Employee,
t1.Salary as Salary
from
Employee as t1,
( select
t2.Name as Department,
max(t1.Salary) as Salary,
t2.Id as Id
from
Employee as t1,
Department as t2
where
t1.DepartmentId = t2.Id
group by t2.Name
) as t2
where
t1.Salary = t2.Salary and
t1.DepartmentId = t2.Id

上面代码就是相当于是,先把每个部门的部门名和最高薪水和部门ID查出来组成一个新表,然后再和Employee表连接。感觉写得有点太冗余了,代码太丑了,不过毕竟也不是搞DBA的,只求结果对就行了。。。


185、部门工资前三高的所有员工 困难

这题很容易能够写出不同部门的工资排名

1
2
3
4
5
6
7
8
9
10
select
t1.DepartmentId as Id,
t2.Name as Department,
t1.Salary as Salary
from
Employee as t1,
Department as t2
where
t1.DepartmentId=t2.Id
group by t2.Name,t1.Salary desc

但是如何按部门取分别的前三高这里卡了很久。

尝试了写函数,但是好像oj执行不了,报错。不知道这个函数这样写有没有用,oj执行不了,也不好调试。只能贴一下了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
create function getTop3(deptId int) returns int
begin
return (
select
t1.Salary as Salary
from
Employee as t1,
Department as t2
where
t1.DepartmentId = t2.Id and
t1.DepartmentId = deptId
group by t2.Name,t1.Salary desc
limit 0,3
);
end

又尝试了下面这样写法,但是得到报错:This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
select 
t2.Name as Department,
t1.Name as Employee,
t1.Salary as Salary
from
Employee as t1,
Department as t2
where
t1.DepartmentId = t2.Id and
t1.Salary in (
select
e.Salary as Salary
from
Employee as e,
Department as d
where
e.DepartmentId = d.Id and
d.Id=t1.DepartmentId
group by d.Name,e.Salary desc
limit 0,3
)
order by t2.Name,t1.Salary desc

最后看了下官方题解,它的做法是对Employee表逐行进行判断是否符合条件,而且它的前三高判断没有用limit,而是转换了一下,变成比当前工资高的人不超过三个,则为前三。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
select 
t2.Name as Department,
t1.Name as Employee,
t1.Salary as Salary
from
Employee as t1,
Department as t2
where
t1.DepartmentId = t2.Id and
3 > (
select
count(distinct Salary)
from
Employee
where
Salary>t1.Salary and
DepartmentId = t1.DepartmentId
)
order by t2.Name,t1.Salary desc

这一题做的有点混乱了,本来按自己的想法来说,前几前几这种问题,一般都是排好序之后用limit,但是好像很多题目都是两表连接,用比较符盒count判断,这个思路要学会转换。还有就是看了一些别人题解,发现也有用自定义变量等这些方法的,姿势还是很多的,哎,太菜了。


瞎说胡扯几句

闲着无事刷的几个题,本来以为leetcode那些上锁的题是通过刷题解锁的。。今天发现居然还要开会员才能解锁。
哎,反正也这么菜,先把免费的题刷了再考虑上锁的吧,然后今天下午知道原来leetcode上锁题要开会员才能解锁,想找个插件把上锁题隐藏起来的,但是只找到一个对英文官网有效的插件,于是又想着能不能找到几个Tamper脚本,找是找到了,但是好像并没啥luan用,不过倒是又引起了我对写TamperMonkey脚本的兴趣,想去搞两遍js然后写个leetcode隐藏上锁题的脚本,2333

今天只写了10题,后面看情况再更新吧。

ヾノ≧∀≦)o 来呀!快活呀!~
-------- 本文结束 --------