Leetcode - MYSQL 專題

Leetcode - MYSQL 專題

        花了點時間把 Leetcode 上 SQL 部分的 非付費題 做了一下,很多例題還是很經典的~所有複雜邏輯都可以在一條語句裏面完成。體會到了 select 語句的博大精深。
        主要涉及到的點有:select別名、select多表、join、case、distinct、count()、where、group by、order by、if、IsNull、日期相關函數。
        select 函數的完整語法如下:

select [ALL|DISTINCT|DISTINCTROW|TOP]
{*|talbe.*|[table.]field1[AS alias1][,[table.]field2[AS alias2][,…]]}
FROM tableexpression[,…][IN externaldatabase]
[WHERE…]
[GROUP BY…]
[HAVING…]
[ORDER BY…]

 

175. Combine Two Tables
        題意:合併兩張表,要求第一張表的行要全,第二張表不管,所以採用 LEFT JOIN。
        鏈接:https://leetcode.com/problems/combine-two-tables/
        題解:利用 left join 進行表的左外連接。

select FirstName, LastName, City, State
from Person left join Address
on Person.PersonId = Address.PersonId;

 

 176. Second Highest Salary
         
題意:輸出第二大的項,如果不存在則返回 null;
         鏈接:https://leetcode.com/problems/second-highest-salary/
         題解:不同數據用 distinct 關鍵字;排序採用 order by;逆序用 desc;limit 用來限定起始和個數;然後用 as 關鍵字定義表的別名;case 和 when 關鍵字做分支判斷,這裏主要有一個 trick 的地方是當不存在第二大的項時需要返回 null。

select 
    case c.cnt
    when 0 then
        null
    else
        c.Salary
    end as SecondHighestSalary
from
    (select count(Salary) as cnt, Salary 
     from 
        (select distinct Salary 
         from Employee 
         order by Salary desc limit 1, 1
        ) as b
    ) as c

 

  177. Nth Highest Salary
         題意:輸出第 N 大的項,如果不存在則返回 null;
         鏈接:https://leetcode.com/problems/nth-highest-salary/
         題解:類似 176,不同之處在於 limit 的參數不能爲表達式,所以 N 需要預先減一。

CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
  set N = N - 1;
  RETURN (
        select 
            case c.cnt
            when 0 then
                null
            else
                c.Salary
            end as xx
        from
            (select count(Salary) as cnt, Salary 
             from 
                (select distinct Salary 
                 from Employee 
                 order by Salary desc limit N, 1
                ) as b
            ) as c
  );
END

 

  178. Rank Scores
         題意:輸出按照 Score 降序排序的表以及排名,相同分數排名一致,且排名都是連續整數;
         鏈接:https://leetcode.com/problems/rank-scores/
         題解:考察的是兩個 select 嵌套:外層 select 表 a 直接按照分數降序排序;內層 select 表 b 統計比表 a 中 score 值大的不同元素個數,再加 1 就是 Rank 值。

select Score, 
    (select count(distinct Score) 
     from Scores as b 
     where a.score < b.score
    ) + 1  as Rank
from Scores as a order by Rank;

 

180. Consecutive Numbers
         
題意:輸出表中有至少三個相鄰表項的數字都相同的數;
         鏈接:https://leetcode.com/problems/consecutive-numbers/
         題解:考察的是技巧。一次 select 可以多張相同的表,然後通過相鄰兩項的判等(下標相差1、Num項相等)篩選出所有滿足條件的三元組 (x, y, z),這裏 x = y = z,所以隨便統計其中一列用 distinct 進行判重篩選輸出即可。

select distinct x as ConsecutiveNums
from
    (select l1.Num as x, l2.Num as y, l3.Num as z
    from Logs l1,
         Logs l2,
         Logs l3
    where l1.Id = l2.Id - 1
        AND l2.Id = l3.Id - 1
        AND l1.Num = l2.Num
        AND l2.Num = l3.Num
     ) as a

 

181. Employees Earning More Than Their Managers
         
題意:給出員工的工資和他的直接上級,求出員工中 “工資高於自己直接上級” 的員工名字;
         鏈接:https://leetcode.com/problems/employees-earning-more-than-their-managers/
         題解:180 的簡化版。一次行 select 兩張表 e1 和 e2,e1 的直接上級編號等於 e2的編號,且 e1 的工資 大於 e2 的工資,統計所有的 e1.Name 即可。

select e1.Name as Employee
from Employee e1, 
     Employee e2 
where e1.ManagerId = e2.Id
    AND e1.Salary > e2.Salary;

 

182. Duplicate Emails
         
題意:輸出所有重複的郵件;
         鏈接:https://leetcode.com/problems/duplicate-emails/
         題解:考察的是 group by,將 Email 進行分組後利用 count(colname) 進行統計。

select Email
from
    (select Id, Email, count(Email) as e 
     from Person group by Email
    ) as x
where x.e > 1;

 

183. Customers Who Never Order
         題意:輸出所有沒有訂單的顧客名;
         鏈接:https://leetcode.com/problems/customers-who-never-order/
         題解:考察多層 select 的嵌套 以及 not in 的使用。注意,不同的顧客可能同名。

select c.Name as Customers 
from Customers as c
where c.Id not in 
    (select n.CustomerId
     from 
        (select CustomerId, c.Id, Name from 
            Orders o,
            Customers c
         where c.Id = CustomerId
        ) as n
    )

 

184. Department Highest Salary
         題意:輸出每個部門裏工資最高的人以及工資信息;
         鏈接:https://leetcode.com/problems/department-highest-salary/
         題解:考察多層 select 的嵌套 以及 group by 分組的應用。

select d.Name as Department, c.Employee, c.Salary 
from
    (select a.DepartmentId, a.Name as Employee, a.Salary as Salary
     from
        Employee as a,
        (select DepartmentId, max(Salary) as Salary 
         from Employee 
         group by DepartmentId
        ) as b
     where 
             a.Salary = b.Salary
        and  a.DepartmentId = b.DepartmentId
    ) as c,
    Department as d
where d.Id = c.DepartmentId

 

185. Department Top Three Salaries
         題意:尋找每個部門中工資前三的進行輸出;
         鏈接:https://leetcode.com/problems/department-top-three-salaries/
         題解:首先,工資前三的人有個特點,就是自己的工資以及比它工資高的(去重後)人數不大於 3。根據這個特點,可以把所有滿足這些條件得人利用 2 個嵌套的 select 加上 group by 和 count (distinct ) 找出它們的 Id。然後,在根據這些Id 去找到它的部門、工資信息。

select d.Name as Department, h.Employee, h.Salary
from
   (select g.DepartmentId, g.Name as Employee, g.Salary
    from
    (
        select a.Id
        from
           (select e1.Id, count(distinct e2.Salary) as cnt
            from
                Employee e1,
                Employee e2
            where e1.DepartmentId = e2.DepartmentId
                and (
                    e1.Salary <= e2.Salary
                )
            group by e1.Id
           ) as a
        where cnt <= 3
    ) as b
    left join Employee g
    on b.Id = g.Id
   ) as h
left join Department d
on h.DepartmentId = d.Id
where not IsNull(d.Name)
order by h.DepartmentId, h.Salary desc
;

 

 

196. Delete Duplicate Emails
         題意:刪除重複郵件,保留編號小的;
         鏈接:https://leetcode.com/problems/delete-duplicate-emails/
         題解:delete from where ...。在 where 語句中進行一些判斷,將右鍵按照 group by 分類後取最小的 Id 組成一個列表,然後刪除的時候判斷 是否在列表中。

delete 
from Person
where Id not in 
(
    select *
    from
    (select min(Id) as Id
     from Person 
     group by Email
    ) as x
);

 

197. Rising Temperature
         題意:給定每一天的溫度,輸出所有比前一天溫度高的那天的編號;
         鏈接:https://leetcode.com/problems/rising-temperature/
         題解:考察多對日期操作函數的運用。a.RecordDate in (select interval 1 day + b.RecordDate) 可以用作判斷 a.RecordDate 是否是 b.RecordDate 的下一天。

select a.Id
from Weather a,
     Weather b
where a.RecordDate in (select interval 1 day + b.RecordDate)
    and a.Temperature > b.Temperature;

 

262. Trips and Users
         題意:給定一張滴滴打車旅程表,乘客表,輸出 2013-10-01 到 2013-10-03 號期間有效乘客的是打車取消率,精確到小數點後2位;
         鏈接:https://leetcode.com/problems/trips-and-users/
         題解:首先用 Trips 和 Users 利用 left join 篩選出一張 noBannedTrips 表代表所有人都是合法的旅程表,用同樣方法得到所有旅程都完成的合法旅程表 noBannedAndNotComletedTrips;然後分別對這兩張表 按照時間進行 group by 和 count(*) 得到時間爲 主key 的旅程表 allTrips 和 取消旅程表allCancellTrips,對這兩張表用時間進行 left join 然後進行計算後用 round 進行四捨五入 ,最後別忘了加上一個時間限制。

select Day, round( if(IsNull(up),0,up) / if(IsNull(dwn),1,dwn), 2 ) as 'Cancellation Rate'
from
(
    select allTrips.Request_at as Day, allTrips.cnt as dwn,  allCancellTrips.cnt as up
    from
        (
         select Request_at, count(*) as cnt
         from 
            (
                select ta.Id, ta.Client_Id, ta.Request_at
                from Trips ta
                left join Users ua
                on ta.Client_Id = ua.Users_Id
                where ua.Banned = "No"
            ) as noBannedTrips
         group by Request_at
        ) as allTrips
    left join
        (
         select Request_at, count(*) as cnt
         from 
            (
                select ta.Id, ta.Client_Id, ta.Request_at
                from Trips ta
                left join Users ua
                on ta.Client_Id = ua.Users_Id
                where ua.Banned = "No"
                and ta.Status != "completed"
            ) as noBannedAndNotComletedTrips
         group by Request_at
        ) as allCancellTrips
    on allTrips.Request_at = allCancellTrips.Request_at
) as result
where result.Day >= '2013-10-01'
    and result.Day <= '2013-10-03';

 

595. Big Countries
         題意:輸出所有人口大於 25000000 或面積大於 3000000 的國家;
         鏈接:https://leetcode.com/problems/big-countries/
         題解:考察條件或語句 where ... or ...。

select name, population, area 
from World
where population > 25000000 
    or area > 3000000;

 

596. Classes More Than 5 Students
         
題意:給定課程和學課的學生,要求輸出學生數大於 4 的那些課的名字;
         鏈接:https://leetcode.com/problems/classes-more-than-5-students/
         題解:考察 group by 按照雙關鍵字去重 以及 利用 group by 分類後用 count 統計的用法 。

select class
from
    (select class, count(class) as cc
     from 
        (select student, class
         from courses group by class, student
        ) as unique_courses
     group by class
    ) as b
where b.cc > 4;

 

601. Human Traffic of Stadium
         
題意:把連續三條記錄中人數過百的天數輸出來;
         鏈接:https://leetcode.com/problems/human-traffic-of-stadium/
         題解:考察的是一次性 select 三個相同的表,然後按照 id 分別進行對比 ,篩選出所有滿足條件的記錄 id ,再用 left join 回原表進行數據查詢。

select t.id, t.date, t.people
from
   (
    select distinct 
        s1.id 
    from 
        stadium s1,
        stadium s2,
        stadium s3
    where   (s1.id + 1 = s2.id
        and s2.id + 1 = s3.id
        and s1.people >= 100
        and s2.people >= 100
        and s3.people >= 100)
       or (s1.id - 1 = s2.id
        and s2.id - 1 = s3.id
        and s1.people >= 100
        and s2.people >= 100
        and s3.people >= 100)
       or (s1.id + 1 = s3.id
        and s1.id - 1 = s2.id
        and s1.people >= 100
        and s2.people >= 100
        and s3.people >= 100)
) as a
left join stadium t
on a.id = t.id;

 

620. Not Boring Movies
         題意:給定一張表,按照條件篩選;
         鏈接:https://leetcode.com/problems/not-boring-movies/
         題解:% 用來取模;where and 用於條件語句;order by 進行排序 。

select *
from cinema
where id % 2 = 1
    and description != "boring"
order by rating desc;

 

626. Exchange Seats
         題意:奇數和偶數的學生交換名字;
         鏈接:https://leetcode.com/problems/exchange-seats/
         題解:考察 if 語句的使用。

select a.id, if( a.id in (select count(*) from seat) and a.id%2=1, a.student, b.student ) as student
from
    (
     select id, student, (FLOOR((id+1)/2)*2-(1-id%2)) as next
     from seat
    ) as a
left join seat b
on a.next = b.id
order by a.id;

 

627. Swap Salary
         題意:將表中的 sex 字段的 男女交換;
         鏈接:https://leetcode.com/problems/swap-salary/
         題解:考察 if 語句的使用: if(條件, 條件滿足執行語句, 條件不滿足執行語句) 。

update salary 
set sex=if(salary.sex = "f", "m", "f");

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章