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_idid 都建议索引),否则递归查询会很慢。

用递归 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 = 5

UNION 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中的事件模型】