探索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 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可以设置每页的条目数量和偏移量,实现分页查询。

六、总结

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

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

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

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

感谢您的支持和理解!

相关推荐
特立独行的猫A6 小时前
用仓颉语言 cj-tauri 框架,五分钟给娃做了个鸿蒙形近字游戏
java·后端·python
AllData公司负责人8 小时前
AI大模型数据开发底座系列说明书,AllData集成Chat2DB开源项目建设AI 数据库分析底座,涵盖AI 洞察/对话SQL/智能视图!
数据库·人工智能·sql·开源·ai 洞察·对话sql
码事漫谈9 小时前
我花了一周时间,看AI公司怎么"管"AI,结果越看越后背发凉
后端
爱学习的程序媛11 小时前
Python常用框架梳理
开发语言·后端·python·ai·web·后端框架·python框架
GISer_Jing11 小时前
Agent核心内容
后端·ai·langchain
隔窗听雨眠12 小时前
MySQL三表JOIN执行内核与优化器决策机制
数据库·mysql·sql优化
budingxiaomoli13 小时前
Spring统一功能处理
java·后端·spring
Decay__13 小时前
SQLServer 索引与 SQL 优化 —— 聚集索引、非聚集索引、覆盖索引、碎片维护与执行计划
运维·数据库·sql·mysql·架构
某鹏13 小时前
网关选型:Go、Java、Graal 谁都不能完胜
后端
用户02478365309714 小时前
从屎山到防线:14 行状态迁移表,给任务系统装上防瞎跳闸门
后端