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");

 

 

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