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

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

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

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