• SQL 也能递归?一文搞懂 Recursive CTE的魔力

SQL 也能递归?一文搞懂 Recursive CTE的魔力

2025-06-10 02:00:10 栏目:宝塔面板 45 阅读

很多人以为递归(Recursive)只属于编程语言,和 SQL 没什么关系。但其实 SQL 中也能实现递归操作,特别是在处理树结构、路径查找时,WITH RECURSIVE 展现出强大威力。本文将带你一步步掌握 SQL 中的递归查询,揭开 Recursive CTE 的神秘面纱!

Recursive CTE(递归公共表表达式)

在 SQL 中,递归公共表表达式(Recursive CTE) 是一种强大的查询手段。通过 WITH RECURSIVE 语法,开发者可以定义一个可以引用自身的查询结构,实现在查询过程中“自我迭代”的效果。

简单来说,SQL 也能“递归”。

不过需要注意的是,递归查询必须设计得当,确保它在某个条件下能够终止。否则,就可能陷入“无限循环”,导致查询无法完成,甚至拖垮数据库性能。

那么,SQL 的递归到底怎么写?能解决哪些实际问题?接下来,我们就从原理、写法,到典型应用场景,一步步带你搞懂 Recursive CTE 的魔力。

来看一个最简单的例子,生成从 1 到 5 的数字序列:

图片

我们来拆解一下这段 SQL 是如何“递归”的:

  • 首先,SELECT 1 AS num 是 递归的起点,称为锚点(Anchor Member),递归从这里开始。
  • 接下来,SELECT num + 1 FROM rec WHERE num < 5 是 递归部分,它会反复执行,直到 num < 5 不再满足为止。
  • UNION ALL 将锚点和递归部分的结果组合起来。

整个查询的执行过程大致如下:

  1. 第一步,输出 1;
  2. 然后执行递归部分,1 + 1 = 2,满足条件,继续;
  3. 依次得到 3、4、5;
  4. 当 num 增加到 6 时,不满足 num < 5,递归终止。

把递归逻辑“套”起来,这次不是 1 到 5,而是 100、200、300……直到 700。核心逻辑没变,只是换了组数字而已。

图片

示例:斐波那契数列(Fibonacci Sequence)

WITH RECURSIVE 不仅可以用于构造数字序列,还可以实现更复杂的递归计算。比如,我们可以利用它来生成前 8 个斐波那契数:

图片

示例:树结构遍历(Tree Traversal)

除了计算数值,WITH RECURSIVE 还可以用于遍历树形结构,这在处理层级数据(如组织架构、分类标签、菜单结构等)时非常常见。

比如,下面是一个“标签(tags)层级结构”的递归遍历案例:

图片

图片

图片

示例:图遍历(Graph Traversal)

借助 WITH RECURSIVE,我们甚至可以在 SQL 中实现任意图结构的遍历(Graph Traversal)。这对于表示如路线网络、依赖关系图、社交图谱等复杂结构非常有用。

不过需要特别注意的是:如果图中存在环(cycle),就必须进行循环检测,否则递归查询可能会陷入死循环,永远无法终止。

一种常见的做法是:在递归过程中记录当前路径,每次延伸路径前,先检查目标节点是否已访问过,从而避免重复走回头路。下面的示例中详细演示这一做法。

图片

图片

需要注意的是,这类图结构中可能包含有向环(directed cycles),比如节点 1、5 和 8 之间就形成了一个闭环。

枚举从某个节点出发的所有路径(Enumerate All Paths from a Node)

下面这个查询展示了如何使用 WITH RECURSIVE 来枚举从节点 1 出发的所有路径:

图片

需要注意的是,这个查询的结果并不限于最短路径。

例如,对于节点 5,结果中既包含直接路径 [1, 5],也包含更长的路径 [1, 3, 5]。

换句话说,它会列出所有可能走通的路径,而不是只保留最短的那一条。如果你希望过滤最短路径或添加路径权重,还需要进一步处理。

图片

枚举两个节点之间的无权最短路径(Enumerate Unweighted Shortest Paths)

WITH RECURSIVE 还可以用来查找两个节点之间的所有无权最短路径。为了保证递归查询在到达目标节点后及时终止,我们可以借助窗口函数,检查当前新增节点中是否已包含目标节点。

下面的查询展示了如何找出从节点 1(起点)到节点 8(终点)之间的所有无权最短路径:

图片

递归不仅属于编程语言,SQL 也能“递归”!借助 WITH RECURSIVE,我们可以优雅地处理数字序列、树结构、图遍历等复杂问题。无论是层级查询,还是路径搜索,Recursive CTE 都是一种强大且灵活的利器。

本文地址:https://www.yitenyun.com/278.html

搜索文章

Tags

数据库 API FastAPI Calcite 电商系统 MySQL Web 应用 异步数据库 数据同步 ACK 双主架构 循环复制 Deepseek 宝塔面板 Linux宝塔 Docker 生命周期 JumpServer JumpServer安装 堡垒机安装 Linux安装JumpServer esxi esxi6 root密码不对 无法登录 web无法登录 序列 核心机制 Windows Windows server net3.5 .NET 安装出错 宝塔面板打不开 宝塔面板无法访问 SSL 堡垒机 跳板机 HTTPS 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 无法访问宝塔面板 Windows宝塔 Mysql重置密码 HTTPS加密 连接控制 机制 ES 协同 Oracle 处理机制 Serverless 无服务器 语言 Spring SQL 动态查询 scp Linux的scp怎么用 scp上传 scp下载 scp命令 OB 单机版 技术 响应模型 缓存方案 缓存架构 缓存穿透 索引 运维 存储 HexHub 架构 InnoDB 日志文件 MIXED 3 分页查询 Rsync 修改DNS Centos7如何修改DNS Redis 电商 系统 异步化 监控 RocketMQ 长轮询 配置 group by 查询 MySQL 9.3 聚簇 非聚簇 Linux 安全 服务器 数据 主库 自定义序列化 防火墙 黑客 sftp 服务器 参数 管理口 数据库锁 开源 PostgreSQL 存储引擎 R edis 线程 SQLark 业务 SQLite-Web SQLite 数据库管理工具 流量 工具 共享锁 线上 库存 预扣 Doris SeaTunnel MVCC 人工智能 向量数据库 推荐系统 ​Redis 机器学习 推荐模型 高可用 加密 场景 信息化 智能运维 • 索引 • 数据库 PG DBA GreatSQL 连接数 Python 网络架构 网络配置 AI 助手 Ftp redo log 重做日志 数据备份 Postgres OTel Iceberg B+Tree ID 字段 优化 万能公式 云原生 RDB AOF Redis 8.0 缓存 Canal 同城 双活 核心架构 订阅机制 prometheus Alert INSERT COMPACT 网络故障 微软 SQL Server AI功能 Hash 字段 不宕机 自动重启 Web SVM Embedding 高效统计 今天这篇文章就跟大家 Netstat Linux 服务器 端口 IT运维 大模型 向量库 Milvus 虚拟服务器 虚拟机 内存 OAuth2 Token Entity 开发 引擎 性能 分库 分表 DBMS 管理系统 MongoDB 容器 sqlmock 崖山 新版本 ZODB Undo Log 单点故障 Redisson 锁芯 LRU mini-redis INCR指令 JOIN openHalo 数据集成工具 容器化 Recursive 窗口 函数 悲观锁 乐观锁 分布式 集中式 模型 SpringAI 数据类型 QPS 高并发 排行榜 排序 Testcloud 云端自动化 磁盘架构 数据脱敏 加密算法 PostGIS 事务 Java Redka 分布式架构 分布式锁​ 聚簇索引 非聚簇索引 启动故障 大表 业务场景 StarRocks 数据仓库 分页 数据结构 EasyExcel MySQL8 意向锁 记录锁 Pottery 原子性 R2DBC InfluxDB AIOPS 1 filelock IT Caffeine CP MCP 开放协议 部署 dbt 数据转换工具 RAG HelixDB 工具链 发件箱模式 池化技术 连接池 SSH 读写 数据分类 网络 Web 接口 字典 对象 优化器 传统数据库 向量化 速度 服务器中毒 Go 数据库迁移 事务隔离 仪表盘 双引擎 数据页 Order 单线程 频繁 Codis 分页方案 排版 Crash 代码 线程安全 LLM 订单 List 类型 日志 Pump 事务同步 UUIDv7 主键 Ansible