本周开始每周一更新LeetCode刷题系列,坚持每周刷一些各方面的面试题,每周一做一篇大致总结,这个系列轻松一点,每篇开篇都放一张好看的图片,大家可以点个赞捧捧场哈,努力坚持一下,争取在面试时造出自己的小火箭,然后开始安心在厂里拧螺丝。
题目链接:点击传送至本题
题目大意:
有Person表(PersonId、FirstName、LastName)
和Addres表(AddressId、PersonId、City、State)
,要求:无论Person是否有地址信息,都要基于两表查询 Person的以下信息:FirstName, LastName, City, State。
解题思路:
考虑到并不是每个人都有地址信息,所以应该使用外连接(本题中是left join)。
# 175. 组合两个表
select FirstName, LastName, City, State
from Person
left join Address
on Person.PersonId=Address.PersonId;
题目链接:点击传送至本题
题目大意:
有Employee表(Id,Salary)
,要求:查询出该表第二高的薪水(查询出的字段名改为SecondHighestSalary ),如果不存在第二高的薪水,查询返回null。
解题思路:
方法1:
先查询一次最高工资,然后在补集中再次查询最高工资即可;
可以这样做是因为sql的聚合函数max自带查询不到返回null的特性。
方法2:
将不同的薪资降序排序,然后使用limit函数截取第二高的工资。
但是可能不存在第二高的薪水,可能表只有一条记录,
所以要考虑当查询不到时返回null值,使用临时表子查询或ifnull函数都可以解决这个问题。
# 176. 第二高的薪水
#方法1:
select max(Salary) as SecondHighestSalary
from Employee
where Salary < (select max(Salary) from Employee);
#方法2:
select ifnull(
(select distinct Salary
from Employee
order by Salary desc
limit 1,1),null) as SecondHighestSalary
题目链接:点击跳转至本题
题目大意:
有Employee表(Id,Name,Salary,ManagerId)
,经理也属于员工,要求:查询出薪水高于他们的经理的员工的姓名。
解题思路:
由于经理也是员工,所以可以通过内连接,自己连接自己,则表1为员工,表2为经理。查询超过经理收入的员工,需要再加上判断条件→表1.Salary>表2.Salary。
# 181. 超过经理收入的员工
select e1.Name as "Employee"
from Employee e1
inner join Employee e2
on e1.ManagerId=e2.Id
where e1.Salary>e2.Salary;
题目链接:点击跳转至本题
题目大意:
有Person表(Id、Email)
,要求查询出Person表中所有重复的电子邮箱。
解题思路:
方法1:
使用group by对Email字段分组后,添加having筛选条件。
方法2:
使用group by和count函数计算每个Email的存在次数作为临时表,然后对临时表添加筛选条件即可。
# 182. 查找重复的电子邮箱
# 方法1:
select Email
from Person
group by Email
having count(Email)>1;
# 方法2:
select Email
from(
select Email,count(Email) num
from Person
group by Email
) as table_1
where num>1;
题目链接:点击跳转至本题
题目大意:
有Customers表(Id、Name)
和Orders表(Id、CustomerId)
,要求:找出所有从不订购任何东西的客户。(即Customers表中Id不在Orders表的CcustomerId字段的Name)
解题思路:
查询从不订购的客户,可以先将订购过商品的客户id查询出来,然后使用not in查询不在此列表中的用户。
# 183. 从不订购的客户
select c.Name as 'Customers'
from Customers c
where c.id not in(select CustomerId from Orders);
题目链接:点击跳转至本题
题目大意:
有Person表(Id、Email)
,要求删除Person表Email字段中所有重复的数据,删除时保留Id最小的那个数据。
解题思路:
通过Email字段将Person表与自身自连接起来,形成笛卡尔积,然后删除Id更大的那些数据,剩下的就是重复且Id最小的数据。
# 196. 删除重复的电子邮箱
delete p1
from(
Person as p1
inner join Person p2
on p1.Email=p2.Email
) where p1.Id>p2.Id;
题目链接:点击跳转至本题
题目大意:
有Weather表(Id、RecordDate(DATE)、Temperature)
,要求查找比昨天温度高的日期的Id。
解题思路:
# 197. 上升的温度
select w1.Id as Id
from Weather w1
inner join Weather w2
on datediff(w1.RecordDate,w2.RecordDate)=1
where w1.Temperature>w2.Temperature;
题目链接:点击跳转至本题
题目大意:
有Employee表(Id、Salary)
,要求查出表中第 n 高的薪水。
解题思路:
针对Employee表的Salary字段降序排列,使用limit限定语句限定范围为第n条。需要注意的是limit的下标默认从0开始,需要设定局部变量解决这一问题。
# 177. 第N高的薪水
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
set n=N-1;
RETURN (
select ifnull(
(select distinct Salary
from Employee
order by Salary desc
limit n,1),null)
);
END
题目链接:点击跳转至本题
题目大意:
有Scores表(Id、Score)
,要求依据Score分数进行排名,如果分数相同,则分数排名相同,且名次之间无间隔。
解题思路1:
给你一个分数X,如何计算出其排名Rank? 首先将所有大于等于X的分数提取为一个集合,然后去重剩下的个数就是X的排名Rank。
解题思路2:
使用mysql8.0之后引入的dense_rank() over()函数
# 178. 分数排名
#方式1:
select s2.Score as Score,
(select count(distinct s1.Score) from Scores s1 where s1.Score>=s2.Score) as "Rank"
from Scores s2
order by s2.Score desc;
# 方式2:
select Score, dense_rank() over (order by Score desc) as "Rank"
from Scores;
题目链接:点击跳转
题目大意:
有Logs表(Id,Num)
,要求查出Num至少连续出现三次的数字。
解题思路:
直接使用sql92语法对Logs做两次自连接,三张表做笛卡尔积,筛选条件是三张表的Id连续的同时Num相等。另外记得加上distinct去重。
# 180. 连续出现的数字
select distinct l1.Num as "ConsecutiveNums"
from
Logs as l1,
Logs as l2,
Logs as l3
where
l1.Id=l2.Id-1
and l2.Id=l3.Id-1
and l1.Num=l2.Num
and l2.Num=l3.Num;
题目链接:点击跳转
题目大意:
有Employee表(Id,Name,Salary,DepartmentId)
和Department表(Id,Name)
,要求查找出每个部门工资最高的员工。
解题思路:
可以先在员工表中的各个部门内查询最高工资作为临时表,然后再把两张表做内连接,方便查询到部门名,此时需要使用IN语句来挂载之前查询到的临时表
# 184. 部门工资最高的员工
select d.Name Department,e.Name Employee,e.Salary Salary
from Employee e
inner join Department d
on e.DepartmentId=d.Id
where (e.DepartmentId,e.Salary) in(
select DepartmentId,max(Salary)
from Employee
group by DepartmentId
);
题目链接:点击跳转
题目大意:
有Employee表(Id,Name,Salary,DepartmentId)
和Department表(Id,Name)
,要求查询出每个部门前三高工资的所有员工。有相同工资的保留。
解题思路:
前三高的薪水意味着有不超过3个工资比这些值大,据此可以写出下列sql语句。然后再连接上部门表,注意连接后的筛选条件即可。
select e1.Name as 'Employee', e1.Salary
from Employee e1
where 3 >
(
select count(distinct e2.Salary)
from Employee e2
where e2.Salary > e1.Salary
);
# 185. 部门工资前三高的所有员工
select
d.Name "Department",e1.Name "Employee",e1.Salary "Salary"
FROM
Employee e1
inner 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
)
题目链接:点击跳转
题目大意:
有Trips出租车表(Id,Client_Id,Driver_Id,City_Id,Status,Request_at)
和Users用户表( Users_Id,Banned,Role)
,要求查出 2013年10月1日 至 2013年10月3日 期间非禁止用户的取消率,保留两位小数。
取消率的计算方式如下:(正常用户取消的订单数量) / (正常用户的订单总数)
解题思路:
将client_id和driver_id各自关联上users_id,同时检测是否被禁止。在此基础上,按照日期分组、查询正常用户取消的订单数量(count(status))、正常用户的订单总数if(T.STATUS=‘completed’,0,1)。
# 262. 行程和用户
select T.Request_at as "Day",round(
sum(if(T.STATUS='completed',0,1))/count(T.STATUS),2
) as "Cancellation Rate"
from Trips as T
join Users as U1 ON (T.client_id =U1.users_id and U1.banned = 'No')
join Users as U2 ON (T.driver_id =U2.users_id and U2.banned = 'No')
where T.request_at BETWEEN '2013-10-01' and '2013-10-03'
group by T.request_at