如何快速掌握MYSQL?附LeetCode上出现频率最高的50道数据库题目详解

Posted 报告,今天也有好好学习

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何快速掌握MYSQL?附LeetCode上出现频率最高的50道数据库题目详解相关的知识,希望对你有一定的参考价值。

如何才能快速掌握mysql?如何熟悉使用SQL以满足日常工作需求?

如果你目前啥也不会,只停留在知道SELECT用于查询的层面的话,又想要快速掌握MYSQL,那么刷题,并且过程中不会什么补什么,就是巩固和提升自己的SQL语言能力最快捷的方法。

LeetCode中有不少题是需要Plus会员才能查看并答题的,所以为避免以后会员过期无法再次查看以及加深自身对题目的理解,进行了MYSQL题目的一次大整理。

LeetCode上题目众多,而本篇筛选出了LetCode上出现频率最高的50道题目,并且按出现频率由高到低整理,每道题实现的具体方法和思路都贴在了代码注释,整理不易,希望大家能够做完这些题目或者看完这篇博客,并从中有所获。

PS:本篇博客主要是使用增删查改中的查询功能。

目录

NO.1 简单 (175. 组合两个表)

https://leetcode-cn.com/problems/combine-two-tables/

# 因为题目要求无论 person 是否有地址信息,所以不能用join,要用left join
select FirstName, LastName, City, State 
from Person 
left join Address on Person.PersonId=Address.PersonId

NO.2 简单 (176. 第二高的薪水)

https://leetcode-cn.com/problems/second-highest-salary/

# 将第一高的工资筛选掉,再次用MAX就可以取到第二高的工资了。
select max(Salary) as SecondHighestSalary from Employee
where Salary <>
(select max(Salary) from Employee)

NO.3 中等 (184. 部门工资最高的员工)

https://leetcode-cn.com/problems/department-highest-salary/

# 先用group by的方法求出部门最高薪资,再接着判断Employee表中哪些数据符合即可,
# 过程中会用到join来连接Employee表和Department表。
select d.Name Department, e.Name Employee, Salary
from  Employee e
join Department d on e.DepartmentId=d.Id
where (DepartmentId, Salary) in
(
    select DepartmentId, MAX(Salary) 
    FROM Employee
    group by DepartmentId
)

NO.4 中等 (177. 第N高的薪水)

https://leetcode-cn.com/problems/nth-highest-salary/

CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
    declare m int;
    set m = N - 1;
    RETURN (
    # 这里主要是考LIMIT的用法:
    /*
    LIMIT 5 等价于 LIMIT 0, 5, 即查询(0+1)到(0+5)的数据,也就是1-5的数据。也就是说这里的0是查询的数据起点的前一位,5是查询的数量。
    LIMIT 2 OFFSET 3 等价于 LIMIT 3 2,即查询(3+1)到(3+2)的数据,也就是4-5的数据。也就是说这里的3是查询的数据起点的前一位,2是查询的数量。
    */
    # 那么要查排名第N的数据,那么就是LIMIT N-1, 1,所以是LIMIT m, 1
    # 最后记得去重
    SELECT IFNULL(
        (SELECT DISTINCT Salary
        FROM Employee 
        ORDER BY Salary DESC
        LIMIT m, 1)
    , NULL)
  );
END

NO.5 中等 (180. 连续出现的数字)

https://leetcode-cn.com/problems/consecutive-numbers/

# 题目要求连续三次及以上,我们只要求出连续三次的数字有哪些即可。
# 取三个Logs表,用来判断。
SELECT DISTINCT L1.Num AS 'ConsecutiveNums'
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

NO.6 困难 (185. 部门工资前三高的所有员工)

https://leetcode-cn.com/problems/department-top-three-salaries/

/*
# 第一种方法是利用窗口函数和dense_rank(),能够对各个部门的工资进行排序
SELECT Department,Employee,Salary
FROM
(
    SELECT
        d.Name AS Department,
        e.Name AS Employee,
        e.Salary AS Salary,
        DENSE_RANK() OVER (PARTITION BY e.DepartmentId ORDER BY e.Salary DESC) AS rk 
    FROM
        Employee e
        JOIN Department d
        ON e.DepartmentId = d.Id
) AS t
WHERE rk<=3
*/
# 第二种方法运用到的思想是:部门中如果不超过两个工资比我的工资高,那我肯定是前三名。
# 比方说如果我是第二名,那只有一个工资比我高(如我工资是8000,部门其他人是9000,7000,9000,6000)
SELECT 
    d.Name AS Department,
    e.Name AS Employee,
    e.Salary AS Salary
FROM
    Employee e
    JOIN Department d
    ON e.DepartmentId = d.Id
WHERE
    e.Id IN
    (
        SELECT
            e1.Id
        FROM
            Employee e1
            LEFT JOIN Employee e2
            on e1.DepartmentId = e2.DepartmentId AND e1.Salary < e2.Salary
        GROUP BY e1.Id
        HAVING COUNT(DISTINCT e2.Salary) <= 2
    )
    AND e.DepartmentId in (SELECT Id from Department)
    order by d.Id asc,e.Salary desc

NO.7 简单 (1777. 每家商店的产品价格)

https://leetcode-cn.com/problems/products-price-for-each-store/

# 同题1795. 每个产品在不同商店的价格,正好相反
# 这里主要是记得要用到聚合函数
# 除了用IF函数,同样的也可以用CASE
SELECT 
    product_id, 
    SUM(IF(store='store1', price, NULL)) store1,
    SUM(IF(store='store2', price, NULL)) store2,
    SUM(IF(store='store3', price, NULL)) store3
FROM
    Products
GROUP BY product_id

NO.8 中等 (178. 分数排名)

https://leetcode-cn.com/problems/rank-scores/

# 第一种方法:利用DENSE_RANK() 窗口函数
/*
SELECT 
    Score,
    DENSE_RANK() OVER (ORDER BY Score DESC) AS 'Rank'
FROM
    Scores
*/
# 第二种方法:主要思想是有几个分数(去重)大于等于我的分数,那这分数就是排第几。
SELECT 
    a.Score,
    (
        SELECT 
            COUNT(DISTINCT b.Score) 
        FROM 
            Scores b
        WHERE a.Score <= b.Score
    ) AS 'Rank'
FROM 
    Scores a
ORDER BY a.Score DESC

NO.9 简单 (181. 超过经理收入的员工)

https://leetcode-cn.com/problems/employees-earning-more-than-their-managers/

# 自连接,将经理和对应的员工处于同一行,再比较即可。
SELECT e1.Name AS 'Employee' 
FROM Employee e1 JOIN Employee e2 ON e1.ManagerId = e2.Id
WHERE e1.Salary > e2.Salary

NO.10 困难 (262. 行程和用户)

https://leetcode-cn.com/problems/trips-and-users/



# 解题思路:首先要将乘客或者司机是非禁止用户的行程筛选出来;
# 接着按日期分组,统计各个日期总订单数;
# 再判断按Status来统计其中取消的订单数量。
SELECT t.Request_at AS 'Day', 
    ROUND((SUM(IF(t.Status='completed', 0, 1))) /
    COUNT(t.Status), 2) AS `Cancellation Rate`
/*
    ROUND((SUM(IF(t.Status='cancelled_by_driver' or t.Status='cancelled_by_client', 1, 0))) /
    COUNT(t.Status), 2) AS `Cancellation Rate`
*/
FROM Trips t
JOIN Users u1 ON (t.Client_Id=u1.Users_Id AND u1.Banned='No')
JOIN Users 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

NO.11 困难 (601. 体育馆的人流量)

https://leetcode-cn.com/problems/human-traffic-of-stadium/

# 窗口函数yyds
# 首先是将人流量大于100的数据筛选出来,然后用窗口函数根据id进行排序(一定要是rank而不是dense_rank)
# 利用id-rank,这样就可以将连续的数据分成同一个组(都拥有同一个order1)
# 接着再利用窗口函数根据order1分组并统计各组数量,大于等于3的数据即为所需数据。
SELECT id, visit_date, people
FROM
(
    SELECT id, visit_date, people, COUNT(*) OVER(PARTITION BY order1) AS order2
    FROM
    (
        SELECT *, (id - rank() OVER(ORDER BY id)) AS order1 FROM
        (
            SELECT * FROM Stadium WHERE people >= 100
        ) AS t1
    ) AS t2
) AS t3
WHERE order2 >= 3

NO.12 简单 (196. 删除重复的电子邮箱)

https://leetcode-cn.com/problems/delete-duplicate-emails/

# 注意是要用到DELETE操作。
DELETE p1
FROM Person p1, Person p2 
WHERE p1.Email=p2.Email AND p1.Id>p2.Id

NO.13 简单 (1179. 重新格式化部门表)

https://leetcode-cn.com/problems/reformat-department-table/

# IF和CASE都可以,同时注意用上SUM函数。
/*
select id,
    SUM(if(month="Jan", revenue, NULL)) as "Jan_Revenue",
    SUM(if(month="Feb", revenue, NULL)) as "Feb_Revenue",
    SUM(if(month="Mar", revenue, NULL)) as "Mar_Revenue",
    SUM(if(month="Apr", revenue, NULL)) as "Apr_Revenue",
    SUM(if(month="May", revenue, NULL)) as "May_Revenue",
    SUM(if(month="Jun", revenue, NULL)) as "Jun_Revenue",
    SUM(if(month="Jul", revenue, NULL)) as "Jul_Revenue",
    SUM(if(month="Aug", revenue, NULL)) as "Aug_Revenue",
    SUM(if(month="Sep", revenue, NULL)) as "Sep_Revenue",
    SUM(if(month="Oct", revenue, NULL)) as "Oct_Revenue",
    SUM(if(month="Nov", revenue, NULL)) as "Nov_Revenue",
    SUM(if(month="Dec", revenue, NULL)) as "Dec_Revenue"
FROM Department
group by id
*/
select id,
    SUM(CASE WHEN month="Jan" THEN revenue ELSE NULL END) as "Jan_Revenue",
    SUM(CASE WHEN month="Feb" THEN revenue ELSE NULL END) as "Feb_Revenue",
    SUM(CASE WHEN month="Mar" THEN revenue ELSE NULL END) as "Mar_Revenue",
    SUM(CASE WHEN month="Apr" THEN revenue ELSE NULL END) as "Apr_Revenue",
    SUM(CASE WHEN month="May" THEN revenue ELSE NULL END) as "May_Revenue",
    SUM(CASE WHEN month="Jun" THEN revenue ELSE NULL END) as "Jun_Revenue",
    SUM(CASE WHEN month="Jul" THEN revenue ELSE NULL END) as "Jul_Revenue",
    SUM(CASE WHEN month="Aug" THEN revenue ELSE NULL END) as "Aug_Revenue",
    SUM(CASE WHEN month="Sep" THEN revenue ELSE NULL END) as "Sep_Revenue",
    SUM(CASE WHEN month="Oct" THEN revenue ELSE NULL END) as "Oct_Revenue",
    SUM(CASE WHEN month="Nov" THEN revenue ELSE NULL END) as "Nov_Revenue",
    SUM(CASE WHEN month="Dec" THEN revenue ELSE NULL END) as "Dec_Revenue"
FROM Department
group by id

NO.14 简单 (182. 查找重复的电子邮箱)

https://leetcode-cn.com/problems/duplicate-emails/

# 相同邮箱但不同Id即为重复数据(记得DISTINCT去重)
SELECT DISTINCT p1.Email
FROM Person p1, Person p2
WHERE p1.Email=p2.Email AND p1.Id<>p2.Id

NO.15 简单 (197. 上升的温度)

https://leetcode-cn.com/problems/rising-temperature/

# 两表之间相互比较即可
SELECT w1.id
FROM Weather w1, Weather w2
WHERE DATEDIFF(w1.recordDate,w2.recordDate)=1 AND w1.Temperature > w2.Temperature

NO.16 中等 (626. 换座位)

https://leetcode-cn.com/problems/exchange-seats/

# 关键在于如何将id转换,这里我用了^(异或)的方法
SELECT IF((SELECT COUNT(*) FROM seat)=id AND id%2<>0, id, (id+1)^1-1) AS id, student
FROM seat
ORDER BY id

NO.17 简单 (620. 有趣的电影)

https://leetcode-cn.com/problems/not-boring-movies/

# 没啥,就是WHERE的条件还有用到排序
SELECT *
FROM cinema
WHERE id%2=1 AND description<>'boring'
ORDER BY rating DESC

NO.18 简单 (627. 变更性别)

https://leetcode-cn.com/problems/swap-salary/

# 只能用UPDATE,然后结合CASE或者IF都可以。
UPDATE salary
SET
    sex = CASE sex
        WHEN 'm' THEN 'f'
        ELSE 'm'
    END;

NO.19 简单 (183. 从不订购的客户)

https://leetcode-cn.com/problems/customers-who-never-order/

# 判断哪些用户ID不在订单表里就行了
SELECT Name Customers FROM Customers
WHERE Id NOT IN (SELECT CustomerId FROM Orders)

NO.20 简单 (511. 游戏玩法分析 I)

https://leetcode-cn.com/problems/game-play-analysis-i/

# 按玩家ID分组,再取MIN(event_date)即可。
SELECT player_id, MIN(event_date) first_login
FROM Activity
GROUP BY player_id

NO.21 简单 (595. 大的国家)

https://leetcode-cn.com/problems/big-countries/

# 简单
SELECT name, population, area 
FROM World
WHERE area > 3000000 or population > 25000000

NO.22 简单 (1873. 计算特殊奖金)

https://leetcode-cn.com/problems/calculate-special-bonus/

# 简单
SELECT employee_id, IF(employee_id%2=1 AND LEFT(name, 1)<>'M', salary, 0) bonus
FROM Employees

NO.23 困难 (1097. 游戏玩法分析 V)

https://leetcode-cn.com/problems/game-play-analysis-v/

# 先取出所有安装日期,然后求出每个安装日期有几个玩家;
# 其中第二天接着玩的有谁(判断玩的日期和安装日期是否相差一天),就可以了。
SELECT first_day AS install_dt, 
    COUNT(DISTINCT player_id) AS installs,
    ROUND((SUM(IF(DATEDIFF(event_date, first_day)=1, 1, 0)))/COUNT(DISTINCT player_id), 2) AS Day1_retention
FROM
(
    SELECT player_id, event_date, MIN(event_date) OVER(PARTITION BY player_id) AS first_day
    FROM Activity
) AS t1
GROUP BY first_day

NO.24 困难 (569. 员工薪水中位数)

https://leetcode-cn.com/problems/median-employee-salary/

# 题目什么东西??不用任何内置函数,抱歉,窗口函数yyds
# 首先要按公司分组,然后对每个公司的员工工资排序(用ROW_NUMBER而不是RANK),然后通过中位数必定大于一半数同时小于一半数+1,得到了中位数。
SELECT Id, Company, Salary
FROM
(
    SELECT *, 
        ROW_NUMBER() OVER(PARTITION BY Company ORDER BY Salary) AS rk, 
        COUNT(*)  OVER(PARTITION BY Company) AS counts_cmy
    FROM Employee
) AS t
WHERE rK>=counts_cmy/2 AND rK<=counts_cmy/2+1

NO.25 中等 (1841. League Statistics)

https://leetcode-cn.com/problems/league-statistics/


# 关键点在于连接的时候可以用or,其余就是相加罢了,不难。
SELECT 
    t.team_name,
    COUNT(*) AS 'matches_played', 
    SUM(
        CASE 
            WHEN (t.team_id=m.home_team_id AND m.home_team_goals>m.away_team_goals) OR
                (t.team_id=m.away_team_id AND m.home_team_goals<m.away_team_goals) 如何快速掌握MYSQL?附牛客网精选的50道SQL题目详解新手推荐

抖音黑帽运营上热门技巧+短视频涨粉+快速掌握热门+快速流量千万

干货收藏!快速掌握用户画像项目的开发流程(附流程图)

3年以上开发者,如何快速掌握 MySQL ?

少儿编程scratch如何快速上手?(附源码)

Python爬虫解析利器Xpath,由浅入深快速掌握(附源码例子)