刷MySQL

该篇是关于LeetCode的MySQL系列

175. 组合两个表

题——简单


表: Person

1
2
3
4
5
6
7
8
9
+-------------+---------+
| 列名 | 类型 |
+-------------+---------+
| PersonId | int |
| FirstName | varchar |
| LastName | varchar |
+-------------+---------+
personId 是该表的主键(具有唯一值的列)。
该表包含一些人的 ID 和他们的姓和名的信息。

表: Address

1
2
3
4
5
6
7
8
9
10
+-------------+---------+
| 列名 | 类型 |
+-------------+---------+
| AddressId | int |
| PersonId | int |
| City | varchar |
| State | varchar |
+-------------+---------+
addressId 是该表的主键(具有唯一值的列)。
该表的每一行都包含一个 ID = PersonId 的人的城市和州的信息。

编写解决方案,报告 Person 表中每个人的姓、名、城市和州。如果 personId 的地址不在 Address 表中,则报告为 null

任意顺序 返回结果表。

结果格式如下所示。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
输入: 
Person表:
+----------+----------+-----------+
| personId | lastName | firstName |
+----------+----------+-----------+
| 1 | Wang | Allen |
| 2 | Alice | Bob |
+----------+----------+-----------+
Address表:
+-----------+----------+---------------+------------+
| addressId | personId | city | state |
+-----------+----------+---------------+------------+
| 1 | 2 | New York City | New York |
| 2 | 3 | Leetcode | California |
+-----------+----------+---------------+------------+
输出:
+-----------+----------+---------------+----------+
| firstName | lastName | city | state |
+-----------+----------+---------------+----------+
| Allen | Wang | Null | Null |
| Bob | Alice | New York City | New York |
+-----------+----------+---------------+----------+
解释:
地址表中没有 personId = 1 的地址,所以它们的城市和州返回 null。
addressId = 1 包含了 personId = 2 的地址信息。

代码:

1
2
3
4
5
# Write your MySQL query statement below
select firstName, lastName, city, state
from Person
left join Address
on Person.personId = Address.personId;

176. 第二高的薪水

题——中等


Employee 表:

1
2
3
4
5
6
7
8
+-------------+------+
| Column Name | Type |
+-------------+------+
| id | int |
| salary | int |
+-------------+------+
在 SQL 中,id 是这个表的主键。
表的每一行包含员工的工资信息。

查询并返回 Employee 表中第二高的薪水 。如果不存在第二高的薪水,查询应该返回 null(Pandas 则返回 None)

查询结果如下例所示。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
输入:
Employee 表:
+----+--------+
| id | salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
输出:
+---------------------+
| SecondHighestSalary |
+---------------------+
| 200 |
+---------------------+

示例 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
Employee 表:
+----+--------+
| id | salary |
+----+--------+
| 1 | 100 |
+----+--------+
输出:
+---------------------+
| SecondHighestSalary |
+---------------------+
| null |
+---------------------+

代码:

limit回顾

1
limit m, n
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 第一种妙一次排序拓展强任意高薪水都能处理,第二种同一表多次排序操作

# Write your MySQL query statement below

# 方法1:使用 排序+limit
select (select salary
from Employee
order by salary desc
limit 1,1) as SecondHighestSalary;

# 方法2:去掉最高再求最高
select max(salary) as SecondHighestSalary
from Employee
where salary < (select max(salary) from Employee);

181. 超过经理收入的员工

题——简单


表:Employee

1
2
3
4
5
6
7
8
9
10
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| name | varchar |
| salary | int |
| managerId | int |
+-------------+---------+
id 是该表的主键(具有唯一值的列)。
该表的每一行都表示雇员的ID、姓名、工资和经理的ID。

编写解决方案,找出收入比经理高的员工。

任意顺序 返回结果表。

结果格式如下所示。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
输入: 
Employee 表:
+----+-------+--------+-----------+
| id | name | salary | managerId |
+----+-------+--------+-----------+
| 1 | Joe | 70000 | 3 |
| 2 | Henry | 80000 | 4 |
| 3 | Sam | 60000 | Null |
| 4 | Max | 90000 | Null |
+----+-------+--------+-----------+
输出:
+----------+
| Employee |
+----------+
| Joe |
+----------+
解释: Joe 是唯一挣得比经理多的雇员。

代码:

1
2
3
4
5
# Write your MySQL query statement below
select a.name Employee
from Employee a
join Employee b
on a.salary > b.salary and a.managerId = b.id;

考虑到SQL语句执行顺序,进行筛选优化

1
2
3
4
5
6
# Write your MySQL query statement below
select a.name Employee
from Employee a
join Employee b
on a.salary > b.salary
where a.managerId = b.id;

问题

为啥使用子查询后效率差的一批

1
2
3
4
5
6
7
8
# Write your MySQL query statement below
select name Employee
from Employee e1
where e1.salary >(
select salary
from Employee e2
where e2.id = e1.managerID
)

image-20240508015457750

182. 查找重复的电子邮箱

题目——简单

表: Person

1
2
3
4
5
6
7
8
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| email | varchar |
+-------------+---------+
id 是该表的主键(具有唯一值的列)。
此表的每一行都包含一封电子邮件。电子邮件不包含大写字母。

编写解决方案来报告所有重复的电子邮件。 请注意,可以保证电子邮件字段不为 NULL。

任意顺序 返回结果表。

结果格式如下例。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
输入: 
Person 表:
+----+---------+
| id | email |
+----+---------+
| 1 | a@b.com |
| 2 | c@d.com |
| 3 | a@b.com |
+----+---------+
输出:
+---------+
| Email |
+---------+
| a@b.com |
+---------+
解释: a@b.com 出现了两次。

代码:

方法一:自连接

1
2
3
4
5
6
# Write your MySQL query statement below
select distinct p1.email
from person p1
left join person p2
on p1.id <> p2.id
where p1.email = p2.email;

方法二:分组(后来突然自己想到的一种方法)

虽然效率低,单字节想到的哦

1
2
3
4
5
# Write your MySQL query statement below
select email Email
from Person
group by email
having count(*) > 1;

183. 从不订购的客户

题目——简单


Customers 表:

1
2
3
4
5
6
7
8
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| name | varchar |
+-------------+---------+
在 SQL 中,id 是该表的主键。
该表的每一行都表示客户的 ID 和名称。

Orders 表:

1
2
3
4
5
6
7
8
9
+-------------+------+
| Column Name | Type |
+-------------+------+
| id | int |
| customerId | int |
+-------------+------+
在 SQL 中,id 是该表的主键。
customerId 是 Customers 表中 ID 的外键( Pandas 中的连接键)。
该表的每一行都表示订单的 ID 和订购该订单的客户的 ID。

找出所有从不点任何东西的顾客。

任意顺序 返回结果表。

结果格式如下所示。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
输入:
Customers table:
+----+-------+
| id | name |
+----+-------+
| 1 | Joe |
| 2 | Henry |
| 3 | Sam |
| 4 | Max |
+----+-------+
Orders table:
+----+------------+
| id | customerId |
+----+------------+
| 1 | 3 |
| 2 | 1 |
+----+------------+
输出:
+-----------+
| Customers |
+-----------+
| Henry |
| Max |

代码:

1
2
3
4
5
6
7
8
# Write your MySQL query statement below
select name Customers
from Customers
where id not in (
select customerId
from Orders
);

178. 分数排名

题——中等(rank内置函数使用)

表: Scores

1
2
3
4
5
6
7
8
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| score | decimal |
+-------------+---------+
在 SQL 中,id 是该表的主键。
该表的每一行都包含了一场比赛的分数。Score 是一个有两位小数点的浮点值。

查询并对分数进行排序。排名按以下规则计算:

  • 分数应按从高到低排列。
  • 如果两个分数相等,那么两个分数的排名应该相同。
  • 在排名相同的分数后,排名数应该是下一个连续的整数。换句话说,排名之间不应该有空缺的数字。

score 降序返回结果表。

查询结果格式如下所示。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
输入: 
Scores 表:
+----+-------+
| id | score |
+----+-------+
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
+----+-------+
输出:
+-------+------+
| score | rank |
+-------+------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
+-------+------+

解题思路

各位可以参考https://blog.csdn.net/qq_41057885/article/details/109176014

1. rank() over

作用:查出指定条件后的进行排名,条件相同排名相同,排名间断不连续。
说明:例如学生排名,使用这个函数,成绩相同的两名是并列,下一位同学空出所占的名次。即:1 1 3 4 5 5 7

2. dense_rank() over

作用:查出指定条件后的进行排名,条件相同排名相同,排名间断不连续。
说明:和rank() over 的作用相同,区别在于dense_rank() over 排名是密集连续的。例如学生排名,使用这个函数,成绩相同的两名是并列,下一位同学接着下一个名次。即:1 1 2 3 4 5 5 6

3. row_number() over

作用:查出指定条件后的进行排名,条件相同排名也不相同,排名间断不连续。
说明:这个函数不需要考虑是否并列,即使根据条件查询出来的数值相同也会进行连续排序。即:1 2 3 4 5 6

使用小提示

dense_rank() over 后面跟排序的依据的列,下面是用了一个排序好的列(order by score desc)。
注意:如果select中有一列是用rank()这类函数,其他的列都会按着他这列规定好的顺序排。

代码

1
2
3
# Write your MySQL query statement below
select score, dense_rank() over (order by score desc) 'rank'
from Scores;

180. 连续出现的数字

题目——中等


表:Logs

1
2
3
4
5
6
7
8
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| num | varchar |
+-------------+---------+
在 SQL 中,id 是该表的主键。
id 是一个自增列。

找出所有至少连续出现三次的数字。

返回的结果表中的数据可以按 任意顺序 排列。

结果格式如下面的例子所示:

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
输入:
Logs 表:
+----+-----+
| id | num |
+----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+----+-----+
输出:
Result 表:
+-----------------+
| ConsecutiveNums |
+-----------------+
| 1 |
+-----------------+
解释:1 是唯一连续出现至少三次的数字。

思路

使用自连接创建三个表,让三个的id连续,然后让num值相等,对于一直连续三次以上的还会重复选取同样的值,因此还需要加distinct去重。

代码

1
2
3
4
5
6
7
8
9
# Write your MySQL query statement below
select distinct l1.num ConsecutiveNums
from Logs l1, Logs l2, Logs l3
where l1.id = l2.id - 1
and l2.id = l3.id -1 -- 先保证id连续

and l1.num = l2.num
and l2.num = l3.num; -- 再保证num连续

184. 部门工资最高的员工

题目——中等

表: Employee

1
2
3
4
5
6
7
8
9
10
11
+--------------+---------+
| 列名 | 类型 |
+--------------+---------+
| id | int |
| name | varchar |
| salary | int |
| departmentId | int |
+--------------+---------+
在 SQL 中,id是此表的主键。
departmentId 是 Department 表中 id 的外键(在 Pandas 中称为 join key)。
此表的每一行都表示员工的 id、姓名和工资。它还包含他们所在部门的 id。

表: Department

1
2
3
4
5
6
7
8
+-------------+---------+
| 列名 | 类型 |
+-------------+---------+
| id | int |
| name | varchar |
+-------------+---------+
在 SQL 中,id 是此表的主键列。
此表的每一行都表示一个部门的 id 及其名称。

查找出每个部门中薪资最高的员工。
任意顺序 返回结果表。
查询结果格式如下例所示。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
输入:
Employee 表:
+----+-------+--------+--------------+
| id | name | salary | departmentId |
+----+-------+--------+--------------+
| 1 | Joe | 70000 | 1 |
| 2 | Jim | 90000 | 1 |
| 3 | Henry | 80000 | 2 |
| 4 | Sam | 60000 | 2 |
| 5 | Max | 90000 | 1 |
+----+-------+--------+--------------+
Department 表:
+----+-------+
| id | name |
+----+-------+
| 1 | IT |
| 2 | Sales |
+----+-------+
输出:
+------------+----------+--------+
| Department | Employee | Salary |
+------------+----------+--------+
| IT | Jim | 90000 |
| Sales | Henry | 80000 |
| IT | Max | 90000 |
+------------+----------+--------+
解释:Max 和 Jim 在 IT 部门的工资都是最高的,Henry 在销售部的工资最高。

思路

  1. 按部门Id分组并选出部门最大薪资的部门Id和salary
  2. 用连接表判断部门Id和salary是否在1表中

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Write your MySQL query statement below
select
d.name Department, e.name Employee, Salary
from
Employee e
join
Department d on departmentId=d.id
where
(departmentId, Salary) in
( select
departmentId, Max(Salary)
from
Employee
group by departmentId
);