本週開始每週一更新LeetCode刷題系列,堅持每週刷一些各方面的面試題,每週一做一篇大致總結,這個系列輕鬆一點,每篇開篇都放一張好看的圖片,大家可以點個贊捧捧場哈,努力堅持一下,爭取在面試時造出自己的小火箭,然後開始安心在廠裏擰螺絲。
文章目錄
數據庫專題
簡單
175. 組合兩個表
題目鏈接:點擊傳送至本題
題目大意:
有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;
176. 第二高的薪水
題目鏈接:點擊傳送至本題
題目大意:
有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
181. 超過經理收入的員工
題目鏈接:點擊跳轉至本題
題目大意:
有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;
182. 查找重複的電子郵箱
題目鏈接:點擊跳轉至本題
題目大意:
有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;
183. 從不訂購的客戶
題目鏈接:點擊跳轉至本題
題目大意:
有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);
196. 刪除重複的電子郵箱
題目鏈接:點擊跳轉至本題
題目大意:
有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;
197. 上升的溫度
題目鏈接:點擊跳轉至本題
題目大意:
有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;
中等
177. 第N高的薪水
題目鏈接:點擊跳轉至本題
題目大意:
有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
178. 分數排名
題目鏈接:點擊跳轉至本題
題目大意:
有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;
180. 連續出現的數字
題目鏈接:點擊跳轉
題目大意:
有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;
184. 部門工資最高的員工
題目鏈接:點擊跳轉
題目大意:
有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
);
困難
185. 部門工資前三高的所有員工
題目鏈接:點擊跳轉
題目大意:
有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
)
262. 行程和用戶
題目鏈接:點擊跳轉
題目大意:
有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