【LeetCode】--- MySQL刷题集合

news/2025/1/22 13:56:28/

1.组合两个表(外连接)

select p.firstName,p.lastName,a.city,a.state 
from Person p left join Address a 
on p.personId = a.personId;

以左边表为基准,去连接右边的表。取两表的交集和左表的全集 

2.第二高的薪水 (子查询、ifnull)

解法一(子查询与LIMIT 子句):

limit的两种写法

limit 起始索引,查询数据的个数

limit 起始索引 offset 查询数据的个数

select 
(select distinct salary from Employee order by salary desc limit 1 offset 1) 
as SecondHighestSalary;

这样的写法就类似于

select 1+2 as SecondHighestSalary;

不需要有数据来源,因为这个表达式的计算结果已经是一个数据了。

这里只是给数据起一个别名。若是子查询数据为空,那么返回的就是null 而不是空了

总之。在 SQL 中使用子查询而没有 FROM 子句的情况通常是为了计算一个表达式或获取一个基于特定逻辑的单一结果,子查询本身提供了数据来源和处理逻辑,无需再通过 FROM 从物理表中获取数据。但在实际应用中,需要考虑性能和可维护性,避免过度复杂的子查询结构。 

解法二(使用 IFNULL 和 LIMIT 子句): 

select ifnull(
(select distinct salary from Employee order by salary desc limit 1,1),null
) 
as SecondHighestSalary;

由于若查询结果为空,返回null

因此使用 ifnull 流程控制函数 更加合适

ifnull(value1,value2)

如果value1为null,就返回value2

如果不为空,就返回value1

注意,若是value1为一个sql语句,要给它加上括号

 3.第N高的薪水(函数、limit不能跟表达式)

 

答案: 

CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
declare M INT;set M = N-1;RETURN (select distinct salary from Employee order by salary desc limit M,1);
END

注意,limit中参数不能写成表达式的形式。也就是不能写成N-1

需要单独定义一个变量 M = N-1 

代码解释 

这个 SQL 代码创建了一个名为 getNthHighestSalary 的函数,该函数接收一个整数参数 N,用于表示要查找第 N 高的薪水。函数的返回值是一个整数,代表第 N 高的薪水值。

变量声明

declare M INT;

变量赋值

set M = N-1;


查询语句

RETURN (select salary from Employee order by salary desc limit M,1
);

 4.分数排名(窗口函数(排名函数dense_rank())

窗口函数的基本结构

<窗口函数>([参数]) OVER ([PARTITION BY <分区列1>, <分区列2>,...][ORDER BY <排序列1> [ASC | DESC], <排序列2> [ASC | DESC],...][ROWS | RANGE <窗口范围说明>]
)

各部分解释

窗口函数

  • 这是核心部分,可以是聚合函数(如 SUM()AVG()COUNT()MAX()MIN() 等)或排名函数(如 RANK()DENSE_RANK()ROW_NUMBER() 等)。
  • OVER 子句

    • 是窗口函数的关键字,表明后面的内容是对窗口的定义。
  • PARTITION BY:
    这是可选的。用于将数据划分为不同的分区,类似于 GROUP BY 的功能,但不会像 GROUP BY 那样对数据进行聚合操作。窗口函数会在每个分区内独立执行。
    例如:partition by ...
    PARTITION BY department 
    会将数据按照部门进行分区,窗口函数将在每个部门内分别计算。
  • ORDER BY:
    通常是必需的,用于对分区内的数据进行排序。这会影响排名函数的结果,以及聚合函数的计算顺序。
    例如:
    ORDER BY salary DESC
    会将分区内的数据按照薪水降序排列。
  • ROWS | RANGE 窗口范围说明:
    这也是可选的,用于进一步定义窗口的范围。
    ROWS 基于物理行,例如
    ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
    表示当前行的前一行到后一行的范围。
    RANGE 基于逻辑值,例如
     RANGE BETWEEN 10 PRECEDING AND 10 FOLLOWING
    表示在当前行的值的基础上,范围是比当前行的值小 10 到大 10 的数据范围。

 排名函数(如 RANK()DENSE_RANK()ROW_NUMBER() 等)。

方法一:排名函数dense_rank()(推荐)

rank()               排名的特点是  1 2 2 4 5 5 5 8 9

dense_rank() 排名的特点是  1 2 2 3 4 5 5 5 6

ROW_NUMBER()      特点是   1 2 3 4 5 6 7 8 9

select s.score,dense_rank() 
over(order by s.score desc) as 'rank' 
from Scores s;

 方法二:使用 COUNT(DISTINCT ...) 的相关子查询

SELECTS1.score,(SELECTCOUNT(DISTINCT S2.score)FROMScores S2WHERES2.score >= S1.score) AS 'rank'
FROMScores S1
ORDER BYS1.score DESC;

这段 SQL 代码的主要目的是为 Scores 表中的每个 score 计算排名。它使用了一个相关子查询来计算排名,排名的依据是大于或等于当前分数的不同分数的数量。

主查询

SELECT S1.score:从 Scores 表中选择 score 列作为主查询的一部分。

子查询部分:

COUNT(DISTINCT S2.score):计算不同分数的数量。
FROM Scores S2:从 Scores 表中选取数据。
WHERE S2.score >= S1.score:这是关键部分,对于主查询中的每个 S1.score,子查询会统计 Scores 表中大于或等于 S1.score 的不同分数的数量。

 最终结果是通过 ORDER BY S1.score DESC 对主查询的结果按照分数降序排列。

5.连续出现的数字 (自连接)

自连接使用场景

1.比较同一表中不同行的数据

  • 示例场景:查找表中相邻行的数据关系,例如找出连续出现的记录。

2.查找父子关系或层次关系

  • 示例场景:在存储了层次结构信息的表中查找父子节点关系。

3.找出重复记录

  • 示例场景:找出表中具有相同数据的行。

4.时间序列分析

  • 示例场景:在存储了时间序列数据的表中,找出连续时间点的数据。

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;

找出至少出现三次的数字。因此进行自连接三次

条件是

第一张表id 等于 第二张表 id-1

第二张表id 等于 第三张表 id-1

第一张表num 等于 第二张表 num

第二张表num 等于 第三张表 num

6.超过经理收入的员工(自连接)

解法一:自连接(隐式where语句)

select e1.name as Employee
from Employee e1,Employee e2 
where e1.managerId = e2.id and e1.salary > e2.salary; 

SQL解释 

表的自连接

from Employee e1, Employee e2

这里将 Employee 表自连接,使用别名 e1 表示员工,e2 表示经理。

where e1.managerId = e2.id and e1.salary > e2.salary;

 e1.managerId = e2.id:
这是自连接的关键条件,它将 e1 表中的 managerId 与 e2 表中的 id 进行连接,意味着 e2 表中的员工是 e1 表中员工的经理。
e1.salary > e2.salary:
这是筛选条件,它确保只选择那些员工的工资(e1.salary)高于其经理的工资(e2.salary)的记录。

 解法二:自连接(显示on语句)

SELECTa.NAME AS Employee
FROM Employee AS a JOIN Employee AS bON a.ManagerId = b.IdAND a.Salary > b.Salary
;

 一、自连接过程:
首先,将 Employee 表自连接,形成笛卡尔积。这意味着 e1 和 e2 表的组合将包含所有可能的行对,即每个 e1 中的行将与 e2 中的所有行组合在一起,总共会有  种组合(假设 Employee 表有 n 行)。对于我们的示例表,会有6的平方 = 36  种组合,但很多组合将不符合条件。

e1.managerId = e2.id:
这一条件将确保 e1 中的员工的经理是 e2 中的员工。例如:
对于 e1 中的 Bob(id = 2,managerId = 1),只有当 e2 中的 id = 1 时,这个条件才满足。所以,Bob 可以和 Alice 组合。 

e1.salary > e2.salary:
在上述满足 e1.managerId = e2.id 的组合中,进一步筛选出员工(e1)工资高于经理(e2)工资的组合:
对于 Bob(e1)和 Alice(e2)的组合:Bob 的工资是 6000,Alice 的工资是 5000,满足 e1.salary > e2.salary,所以 Bob 会被选中。 

注意e1.managerId = e2.id 与 e1.id = e2.managerId的区别

e1.managerId = e2.id 
这个条件表示 e2 表中的员工是 e1 表中员工的经理。也就是说,通过 managerId 建立了从员工(e1)到其经理(e2)的关联。 

e1.id = e2.managerId:
这个条件表示 e1 表中的员工是 e2 表中员工的经理。与第一个语句相反,这里是通过 managerId 建立了从经理(e1)到其下属员工(e2)的关联。 

7.找到重复的电子邮箱(自连接 | group by... having)

法一:自连接(效率低一点)

select distinct p1.email as Email 
from Person p1, Person p2 
where p1.id <> p2.id and p1.email = p2.email; 

法二:(GROUP BY 和临时表) (比自连接效率高)

表子查询

select email, count(*) as num from Person group by email

得到临时表

再根据这个表找到email数量大于 1 的 email就可以了

select  email as Email 
from  (select email, count(*) as num from Person group by email) t
where num > 1;

法三、使用 GROUP BY 和 HAVING 条件 (效率相对高一点)

select email from Person 
group by email 
having count(*) > 1;

分完组之后,再用having count(*)来计算组内的行数。

再筛选组内行数大于1的email 

 8.从不订购的客户(is null)

 注意:判断是否为null 要用 is 而不是 =

法一:列子查询(子查询返回的是一列数据)

select name as Customers from Customers
where id 
not in (select customerId from Orders);

法二:左连接(Left Join)

select name as Customers from Customers c
left join Orders o 
on c.id = o.customerId  where customerId is null; 

9.部门工资最高的员工 

法一:隐式内连接

select d.name Department,e.name Employee,e.salary 
from Employee e,Department d
where e.departmentId = d.id
and e.salary >= 
all (select salary from Employee t where e.departmentId = t.departmentId);

e.salary >= 
all (select salary from Employee t where e.departmentId = t.departmentId);

员工薪资 ≥ 相同部门的薪资。

法二、窗口函数(MAX()+行子查询) 

select d.name AS 'Department',e.name AS 'Employee',Salary
FROM Employee e JOIN Department d ON e.DepartmentId = d.Id
where (e.DepartmentId , Salary) in
(select DepartmentId, MAX(Salary) from Employee 
GROUP BY DepartmentId);

 where 条件 绑定了部门 id 和 薪资水平 in

查出来的 部门id 和最高的薪资水平。

select DepartmentId, MAX(Salary) from Employee 
GROUP BY DepartmentId;

法三:窗口函数(dense_rank() partition by)(推荐)

select d.name AS 'Department',e.name AS 'Employee',e.salary Salary
from 
(select *,dense_rank()  over(partition by departmentId order by salary desc) as erank 
from Employee) e ,Department d 
where e.departmentId = d.Id
and erank <= 1;

10.部门工资前三高的所有员工

 

法一:窗口函数(dense_rank()) 

select d.name as Department, e.name as Employee,salary Salary from
(select *, dense_rank()
over(partition by departmentId order by salary desc) as erank
from Employee) e
left join Department d on e.departmentId = d.id
where erank <= 3;

其中 

select *, dense_rank()
over(partition by departmentId order by salary desc) as erank
from Employee;

#根据部门id分组,再对组内按照薪水从大到小排序,并生成对应的排名编号

再右连接Deparment表 输出排名编号≤3的

 


http://www.ppmy.cn/news/1565231.html

相关文章

Java程序基础⑧抽象类+Object类+内部类

目录 1. 抽象类 1.1 抽象类的概念 1.2 抽象类的语法 1.3 抽象类的特性 1.4 抽象类的作用 2. Object类 2.1 Object类的概念 2.2 获取对象信息toString方法 2.3 对象比较equals方法 2.4 获取位置hashcode方法 3. 内部类 3.1 内部类的概念 3.2 内部类的种类 3.2.1 …

二分查找法(Binary Search)

二分查找法&#xff08;Binary Search&#xff09;是一种高效的查找算法&#xff0c;适用于在有序数组或列表中查找特定元素。它的基本思想是通过不断将搜索范围减半来快速定位目标值。 算法步骤 初始化&#xff1a;设定搜索范围的起始点 left 和结束点 right&#xff0c;初始时…

DM8 SQL 错误 [22000]: 锁超时

问题描述 DM管理工具删除会卡死DBeaver删除会一直加载中使用truncate语句会显示SQL 错误 [22000]: 锁超时使用如下语句也没有用 select a.*,b.NAME,c.SESS_ID, sp_close_session( || c.SESS_ID || ); AS CLOSE_SESSION_COMMAND from v$lock a left join sysobjects b on b.IDa…

从MySQL迁移到PostgreSQL的完整指南

1.引言 在现代数据库管理中&#xff0c;选择合适的数据库系统对业务的成功至关重要。随着企业数据量的增长和对性能要求的提高&#xff0c;许多公司开始考虑从MySQL迁移到PostgreSQL。这一迁移的主要原因包括以下几个方面&#xff1a; 1.1 性能和扩展性 PostgreSQL以其高性能…

Linux容器(初学了解)

目录 一、容器 1.1、容器技术 1.2、容器和虚拟机之间的差异 1.3、Rootless 和 Rootful 容器 1.4、设计基于容器的架构 1.5、容器管理工具 1.6、容器镜像和注册表 1.7、配置容器注册表 1.8、使用容器文件构建容器镜像 二、部署容器 2.1、Podman 实用程序 2.2、安装容…

root用户Linux银河麒麟服务器安装vnc服务

安装必要桌面环境组件 yum install mate-session-manager -y mate-session #确定是否安装成功安装vnc服务器 yum install tigervnc-server -y切换到root为root得vnc设置密码 su root vncpasswd给root用户设置vnc服务器文件 vi /etc/systemd/system/vncserver:1.service [Un…

Gin 源码概览 - 路由

本文基于gin 1.1 源码解读 https://github.com/gin-gonic/gin/archive/refs/tags/v1.1.zip 1. 注册路由 我们先来看一段gin代码&#xff0c;来看看最终得到的一颗路由树长啥样 func TestGinDocExp(t *testing.T) {engine : gin.Default()engine.GET("/api/user", f…

9. 神经网络(一.神经元模型)

首先&#xff0c;先看一个简化的生物神经元结构&#xff1a; 生物神经元有多种类型&#xff0c;内部也有复杂的结构&#xff0c;但是可以把单个神经元简化为3部分组成&#xff1a; 树突&#xff1a;一个神经元往往有多个树突&#xff0c;用于接收传入的信息。轴突&#xff1a;…