SQL 如何实现层级结构(树形数据)?
发布时间 - 2026-01-20 00:00:00 点击率:次SQL实现树形结构主要用递归查询,核心是WITH RECURSIVE(标准)或数据库特有语法;常用自引用表设计,含parent_id外键,根节点为NULL;需对parent_id和id建索引以提升递归查询性能。
SQL 实现层级结构(树形数据)主要靠递归查询,核心是用 WITH RECURSIVE(标准 SQL)或数据库特有语法(如 SQL Server 的 CTE、Oracle 的 CONNECT BY、MySQL 8.0+ 的递归 CTE)。关键不在“怎么写”,而在“怎么设计”和“怎么查”。
用自引用表结构存树
最常见方式是单表加一个指向父节点的外键字段(比如 parent_id),根节点该字段为 NULL 或 0。
例如:
CREATE TABLE categories ( id INT PRIMARY KEY, name VARCHAR(50), parent_id INT NULL, FOREIGN KEY (parent_id) REFERENCES categories(id) );
这种结构简单、易维护,适合变动不频繁、深度适中的树(如菜单、分类、组织架构)。注意:要建好索引(parent_id 和 id 都建议索引),否则递归查询会很慢。
用递归 CTE 查任意层级路径
以 PostgreSQL / MySQL 8.0+ / SQL Server 为例,查某个节点的所有祖先或所有后代,都用 WITH RECURSIVE:
查某节点(id=5)的所有祖先(向上遍历):
WITH RECURSIVE tree AS ( -- 基础查询:从目标节点开始 SELECT id, name, parent_id, 0 AS level FROM categories WHERE id = 5UNION ALL
-- 递归部分:找 parent_id 对应的记录 SELECT c.id, c.name, c.parent_id, t.level + 1 FROM categories c INNER JOIN tree t ON c.id = t.parent_id ) SELECT * FROM tree ORDER BY level DESC;
- 基础查询必须先命中起点(不能是空结果集)
- 递归部分的 JOIN 条件必须让结果逐步收敛(比如用 c.id = t.parent_id 向上找)
- level 字段可用来排序或限制深度(加 WHERE t.level 防无限循环)
查子树(向下展开)并带缩进显示
展示完整子树时,常需要层级缩进。可在递归中拼接路径或生成空格:
WITH RECURSIVE tree AS ( SELECT id, name, parent_id, 0 AS level, CAST(name AS CHAR(200)) AS path FROM categories WHERE parent_id IS NULL -- 根节点UNION ALL
SELECT c.id, c.name, c.parent_id, t.level + 1, CONCAT(t.path, ' → ', c.name) FROM categories c INNER JOIN tree t ON c.parent_id = t.id ) SELECT REPEAT(' ', level) || name AS indented_name, id, parent_id, level FROM tree ORDER BY path;
这样输出就自带层级视觉效果。注意字符串长度(CAST/CONCAT)和数据库函数差异(MySQL 用 CONCAT,PostgreSQL 用 ||,SQL Server 用 +)。
替代方案:闭包表 or 路径枚举
如果树频繁查询、少修改,且对性能敏感,可考虑预计算方案:
-
闭包表(Closure Table):单独一张表存所有祖先-后代关系(ancestor, descendant, depth),
查子树/祖先极快,但增删节点需批量更新关联行
- 路径枚举(Path Enumeration):在节点里存完整路径(如 "/1/3/5"),用 LIKE 快速查子树(path LIKE '/1/3/%'),但路径更新成本高、不便于校验完整性
这两种不是“纯 SQL 树形查询”,而是用空间换时间的设计策略,适合读多写少场景。
# mysql
# oracle
# go
# sql
# 架构
# NULL
# 字符串
# 递归
# 循环
# 闭包
# table
# postgresql
# 数据库
# 子树
# 遍历
# 而在
# 可在
# 为例
# 自带
# 都用
# 这两种
# 必须先
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
javascript中的try catch异常捕获机制用法分析
JavaScript数据类型有哪些_如何准确判断一个变量的类型
如何快速搭建自助建站会员专属系统?
Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程
Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验
Windows Hello人脸识别突然无法使用
在线ppt制作网站有哪些软件,如何把网页的内容做成ppt?
Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置
Laravel怎么集成Log日志记录_Laravel单文件与每日日志配置及自定义通道【详解】
Laravel事件监听器怎么写_Laravel Event和Listener使用教程
网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?
JavaScript如何实现错误处理_try...catch如何捕获异常?
如何在IIS管理器中快速创建并配置网站?
高端企业智能建站程序:SEO优化与响应式模板定制开发
Python文件异常处理策略_健壮性说明【指导】
javascript中的数组方法有哪些_如何利用数组方法简化数据处理
教你用AI润色文章,让你的文字表达更专业
JavaScript如何实现继承_有哪些常用方法
Laravel如何实现用户角色和权限系统_Laravel角色权限管理机制
Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程
Laravel如何使用Telescope进行调试?(安装和使用教程)
非常酷的网站设计制作软件,酷培ai教育官方网站?
MySQL查询结果复制到新表的方法(更新、插入)
高防服务器如何保障网站安全无虞?
Laravel如何配置任务调度?(Cron Job示例)
佛山网站制作系统,佛山企业变更地址网上办理步骤?
Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程
新三国志曹操传主线渭水交兵攻略
C语言设计一个闪闪的圣诞树
如何续费美橙建站之星域名及服务?
如何在IIS中配置站点IP、端口及主机头?
如何快速登录WAP自助建站平台?
laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程
教学论文网站制作软件有哪些,写论文用什么软件
?
Laravel表单请求验证类怎么用_Laravel Form Request分离验证逻辑教程
Laravel集合Collection怎么用_Laravel集合常用函数详解
Laravel如何配置和使用缓存?(Redis代码示例)
如何在七牛云存储上搭建网站并设置自定义域名?
在线制作视频网站免费,都有哪些好的动漫网站?
1688铺货到淘宝怎么操作 1688一键铺货到自己店铺详细步骤
Python面向对象测试方法_mock解析【教程】
常州企业网站制作公司,全国继续教育网怎么登录?
laravel怎么实现图片的压缩和裁剪_laravel图片压缩与裁剪方法
开心动漫网站制作软件下载,十分开心动画为何停播?
Laravel中Service Container是做什么的_Laravel服务容器与依赖注入核心概念解析
jQuery中的100个技巧汇总
Laravel怎么使用Blade模板引擎_Laravel模板继承与Component组件复用【手册】
浅谈Javascript中的Label语句
如何在Ubuntu系统下快速搭建WordPress个人网站?
javascript事件捕获机制【深入分析IE和DOM中的事件模型】


