探索MySQL 递归查询,优雅的给树结构分页

一、概述

递归查询是一种在数据库中处理具有层级结构数据的技术。它通过在查询语句中嵌套引用自身,以实现对嵌套数据的查询。递归查询在处理树状结构、父子关系或层级关系的数据时非常有用。

MySQL中,递归查询可以使用WITH RECURSIVE语句来实现。该语句允许我们定义一个递归查询,并在查询中引用自身。

递归查询通常包含两个部分:基础查询递归查询

graph LR A(递归查询) B(基础查询) C(递归查询) A ---> B A ---> C style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px
  • 基础查询是指查询的起始点,它返回递归查询中的初始结果集。

  • 递归查询部分定义了如何从基础查询的结果集中继续查询下一层的数据,直到满足终止条件为止。

注意:MySQL是在8.0才引入的窗口函数功能;属于MySQL8的新特性

二、结构

递归查询通常包含以下几个关键元素:

graph LR A(递归查询关键元素) B(初始查询) C(递归查询) D(终止条件) A ---> B A ---> C A ---> D style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px
  • 初始查询Anchor Query):这是递归查询的起点,返回初始结果集。它是递归查询的第一步。

  • 递归查询Recursive Query):这是递归查询的核心部分,它引用自身并定义了如何从上一层的结果集中继续查询下一层的数据。递归查询通常包含一个递归关系,通过引用父节点与子节点之间的关联来构建数据的层级结构。

  • 终止条件Termination Condition):这是递归查询的结束条件,用于指定何时停止递归查询。终止条件通常是基于已查询的数据的某种条件或限制。

三、递归查询的执行过程

递归查询的执行过程如下:

flowchart TD subgraph 初始查询 A[执行初始查询] end subgraph 递归查询 B[执行递归查询] C[将结果集与初始结果集合并] D[满足终止条件吗?] end subgraph 输出结果 E[输出最终结果集] end A --> B B --> C C --> D D -- 否 --> B D -- 是 --> E
  1. 执行初始查询,获取初始结果集。

  2. 将初始结果集作为递归查询的输入,执行递归查询,并将结果集与初始结果集合并。

  3. 重复执行递归查询,直到满足终止条件为止。

四、递归查询的应用场景

递归查询在许多应用场景中都是非常有用的。以下是一些常见的递归查询的应用场景:

graph LR A(递归查询的应用场景) B(组织架构和层级关系) C(文件系统和目录结构) D(树形结构数据) E(社交网络和关系图谱) F(有向图和路径查找) A ---> B A ---> C A ---> D A ---> E A ---> F style B fill:#FFC0CB,stroke:#FFC0CB,stroke-width:2px style C fill:#FFA07A,stroke:#FFA07A,stroke-width:2px style D fill:#FFFFE0,stroke:#FFFFE0,stroke-width:2px style E fill:#98FB98,stroke:#98FB98,stroke-width:2px style F fill:#B2FFFF,stroke:#B2FFFF,stroke-width:2px

注意:以上内容只是递归查询的一些常见应用场景,实际上,递归查询可以适用于任何具有层级或递归结构的数据。通过合理地设计和应用递归查询,可以更轻松地处理复杂的数据关系和层次结构,提供更高效和灵活的数据访问和分析能力。

五、一个案例演示递归查询

为了更好的认识递归查询,这里使用一个简单的组织架构来演示一下递归查询是怎么实现的。

5.1 创建一个组织架构表

sql 复制代码
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='公司组织架构';

5.2 在这个组织架构表里面插入一些数据

sql 复制代码
INSERT INTO `hytto_cs`.`organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (1, '集团总部', NULL, 1);
INSERT INTO `hytto_cs`.`organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (2, '华北分公司', 1, 2);
INSERT INTO `hytto_cs`.`organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (3, '华南分公司', 1, 2);
INSERT INTO `hytto_cs`.`organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (4, '华北-北京公司', 2, 3);
INSERT INTO `hytto_cs`.`organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (5, '华北-内蒙公司', 2, 3);
INSERT INTO `hytto_cs`.`organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (6, '华南-广州公司', 3, 3);
INSERT INTO `hytto_cs`.`organization`(`org_id`, `org_name`, `parent_id`, `org_level`) VALUES (7, '华南-深圳公司', 3, 3);

5.3 使用递归查询分页查看我们的组织架构

sql 复制代码
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 NULL条件查找根节点,选择了根节点的组织信息(org_id, org_name, parent_id, org_level)

  • 然后,使用UNION ALLINNER 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进行排序。通过LIMITOFFSET可以设置每页的条目数量和偏移量,实现分页查询。

六、总结

递归查询在处理父子结构、树状结构或层级关系的数据时非常有用。它允许我们轻松地查询所有层级的数据,无论层级有多深。递归查询还可以用于处理分页查询、路径查询、层级计算等各种复杂的查询需求。

需要注意的是,递归查询可能会占用较多的系统资源,并且在处理大型数据集时可能会导致性能问题。因此,在使用递归查询时,需要谨慎设计和优化查询,以确保查询的效率和性能。

希望本文对您有所帮助。如果有任何错误或建议,请随时指正和提出。

同时,如果您觉得这篇文章有价值,请考虑点赞和收藏。这将激励我进一步改进和创作更多有用的内容。

感谢您的支持和理解!

相关推荐
White_Mountain5 分钟前
在Ubuntu中配置mysql,并允许外部访问数据库
数据库·mysql·ubuntu
老王笔记10 分钟前
GTID下复制问题和解决
mysql
清平乐的技术专栏29 分钟前
Hive SQL 查询所有函数
hive·hadoop·sql
Lojarro2 小时前
【Spring】Spring框架之-AOP
java·mysql·spring
isolusion2 小时前
Springboot的创建方式
java·spring boot·后端
TianyaOAO2 小时前
mysql的事务控制和数据库的备份和恢复
数据库·mysql
Ewen Seong2 小时前
mysql系列5—Innodb的缓存
数据库·mysql·缓存
zjw_rp2 小时前
Spring-AOP
java·后端·spring·spring-aop
TodoCoder3 小时前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
凌虚4 小时前
Kubernetes APF(API 优先级和公平调度)简介
后端·程序员·kubernetes