递归查询是一种在数据库中处理具有层级结构数据的技术。它通过在查询语句中嵌套引用自身,以实现对嵌套数据的查询。递归查询在处理树状结构、父子关系或层级关系的数据时非常有用。
在MySQL
中,递归查询可以使用WITH RECURSIVE
语句来实现。该语句允许我们定义一个递归查询,并在查询中引用自身。
递归查询通常包含两个部分:基础查询 和递归查询 。
基础查询是指查询的起始点,它返回递归查询中的初始结果集。 递归查询部分定义了如何从基础查询的结果集中继续查询下一层的数据,直到满足终止条件为止。 “
注意:MySQL
是在8.0 才引入的窗口函数功能;属于MySQL8的新特性
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/ruoyi-vue-pro 视频教程:https://doc.iocoder.cn/video/ “
递归查询通常包含以下几个关键元素:
初始查询 (Anchor Query
):这是递归查询的起点,返回初始结果集。它是递归查询的第一步。递归查询 (Recursive Query
):这是递归查询的核心部分,它引用自身并定义了如何从上一层的结果集中继续查询下一层的数据。递归查询通常包含一个递归关系,通过引用父节点与子节点之间的关联来构建数据的层级结构。终止条件 (Termination Condition
):这是递归查询的结束条件,用于指定何时停止递归查询。终止条件通常是基于已查询的数据的某种条件或限制。基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/yudao-cloud 视频教程:https://doc.iocoder.cn/video/ 递归查询的执行过程如下:
将初始结果集作为递归查询的输入,执行递归查询,并将结果集与初始结果集合并。 递归查询在许多应用场景中都是非常有用的。以下是一些常见的递归查询的应用场景:
“
注意:以上内容只是递归查询的一些常见应用场景,实际上,递归查询可以适用于任何具有层级或递归结构的数据。通过合理地设计和应用递归查询,可以更轻松地处理复杂的数据关系和层次结构,提供更高效和灵活的数据访问和分析能力。
为了更好的认识递归查询,这里使用一个简单的组织架构来演示一下递归查询是怎么实现的。
CREATE TABLE `organization` ( `org_id` int NOT NULL COMMENT '主键' , `org_name` varchar(100 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '组织名称' , `parent_id` int DEFAULT NULL COMMENT '父组织id' , `org_level` int DEFAULT NULL COMMENT '组织级别' , PRIMARY KEY (`org_id`) , KEY `parent_id` (`parent_id`) , CONSTRAINT `organization_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `organization` (`org_id`) ) ENGINE =InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='公司组织架构' ;
INSERT INTO `organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (1 , '集团总部' , NULL, 1 ); INSERT INTO `organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (2 , '华北分公司' , 1 , 2 ); INSERT INTO `organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (3 , '华南分公司' , 1 , 2 ); INSERT INTO `organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (4 , '华北-北京公司' , 2 , 3 ); INSERT INTO `organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (5 , '华北-内蒙公司' , 2 , 3 ); INSERT INTO `organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (6 , '华南-广州公司' , 3 , 3 ); INSERT INTO `organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (7 , '华南-深圳公司' , 3 , 3 );
WITH RECURSIVE RecursiveOrganization AS ( SELECT org_id, org_name, parent_id, org_level FROM organization WHERE parent_id IS NULL -- 查找根节点 UNION ALL SELECT o.org_id, o.org_name, o.parent_id, o.org_level FROM organization o INNER JOIN RecursiveOrganization ro ON ro.org_id = o.parent_id ) SELECT org_id, org_name, parent_id, org_level FROM RecursiveOrganization ORDER BY org_id LIMIT 2 OFFSET 0 ; -- 设置每页的条目数量和偏移量
解析一下这个SQL
:
首先,使用WITH RECURSIVE
子句创建了一个名为RecursiveOrganization
的递归查询视图。在初始查询部分,通过WHERE parent_id IS NUL
L条件查找根节点,选择了根节点的组织信息(org_id, org_name, parent_id, org_level)
。 然后,使用UNION ALL
和INNER JOIN
将递归查询与organization
表连接起来,逐级递归获取下级组织的信息。通过SELECT o.org_id, o.org_name, o.parent_id, o.org_level
选择下级组织的信息,并使用ON ro.org_id = o.parent_id
指定连接条件。 最后,从RecursiveOrganization
视图中选择所需的组织架构数据,并使用ORDER BY
对结果按org_id
进行排序。通过LIMIT
和OFFSET
可以设置每页的条目数量和偏移量,实现分页查询。 递归查询在处理父子结构、树状结构或层级关系的数据时非常有用。它允许我们轻松地查询所有层级的数据,无论层级有多深。递归查询还可以用于处理分页查询、路径查询、层级计算等各种复杂的查询需求。
需要注意的是,递归查询可能会占用较多的系统资源,并且在处理大型数据集时可能会导致性能问题。因此,在使用递归查询时,需要谨慎设计和优化查询,以确保查询的效率和性能。