MySQL中的常用树形结构设计总结
作者:lvhui321 发布时间:2024-01-18 22:05:31
常用树形结构设计总结
开发中,经常会遇到树形结构的设计,所谓的树形结构,其实就是数据与关系的设计,本文用来总结常用的树形结构设计
1. 递归表
id | pid | node_name |
1 | 0 | 父1 |
2 | 0 | 父2 |
3 | 1 | 子1 |
4 | 2 | 子2 |
注意:在数据量少的情况下,一次加载所有节点,无大影响;数据量大的情况,建议懒加载(逐层加载)
2.路径枚举
id | pid | node_name | pids |
1 | 0 | 父1 | 0,1 |
2 | 0 | 父2 | 0,2 |
3 | 1 | 子1 | 0,1 |
4 | 2 | 子2 | 0,2 |
3.数据与关系分开存
数据表
id | node_name |
1 | 节点1 |
2 | 节点2 |
3 | 节点3 |
关系表
id | pid_id | descendant | level(层次) |
1 | 1 | 2 | 1 |
2 | 2 | 3 | 2 |
MySQL树形结构(多级菜单)查询设计方案
工作中(尤其是传统项目中)经常遇到这种需要,就是树形结构的查询(多级查询),常见的场景有:组织架构(用户部门)查询 和 多级菜单查询
比如,菜单分为 * ,一级菜单、二级菜单、 * 菜单,要求用户按树形结构把各级菜单查询出来。
如下图所示
对于层级固定,层级数少的,一般3级,需求实现很简单,先查询最小子级,再依次查询上级,最后再组装返回给前端就是了。
那么问题来了,如果层级数很大,10级,或者干脆层级不确定,有的3级,有的5级,有的8级,与之前的层级固定,层级数相比,显然问题更复杂了,我们来看看这种怎么处理
* 查询(层级固定,层级数少)
这种情况,我们只需要一张表,就叫它树形表吧:
CREATE TABLE tree (
id int not null auto_increment,
name varchar(50) not null comment '名称',
parent_id int not null default 0 comment '父级id',
level int not null default 1 comment '层级,从1开始',
created datetime,
modified datetime
);
* 查询过程:查询出 * tree, 根据 * tree的 parent_id 查询出二级tree, 同样的方式再去查询出一级tree, 后端组装成树状数据,返回给前端。
多级查询(层级不固定/层级很深)
这种情况,我们首先想到的就是子查询或者联表查询,但是肯本不能在实际开发中使用,原因大家都知道:
sql语句复杂,容易出错
性能问题,可能会被领导干
所以最好的方式就是,加一张表 tree_depth,来维护层级深度关系。
CREATE TABLE tree_depth (
id int not null auto_increment,
root_id int not null default 0 comment '根节点(祖先节点)id',
tree_id int not null default 0 comment '当前节点id',
depth int not null default 0 comment '深度(当前节点 tree_id 到 根节点 root_id 的深度)',
created datetime
);
表中 depth 字段表示的是: 当前节点 tree_id 到 根节点 root_id 的深度,不是当前节点所在整个分支的深度,所有节点相对于自身的深度都是0
有了 tree_depth 表后,查询一个N级节点的组织数据就方便了:
遍历整个树:
直接查 tree 中所有 level = 1 的节点,在出去这些节点的 id 根据 parent_id 去查下级节点, 查询完所有的节点,就可以组装成一个完整的树状图返回给前端
节点搜索(查找出这个节点所在的整个分支)
从 tree 表查询出节点 treeN
select * from tree where id = N
根据 treeN 的 id 值,到 tree_depth 表查询出它的 根节点id:
select root_id from tree_depth where tree_id = #{treeId}
根据 root_id 查询 tree_depth 的 所有当前节点分支数据
select * from tree_depth where root_id = #{rootId}
从查询出 tree_depth 表数据中取出所有当前节点 tree_id
select * from tree where id in (?,?,?)
组装所在分支树状结构
来源:https://blog.csdn.net/lvhui321/article/details/124008880


猜你喜欢
- 前言近来chatGPT挺火的,也试玩了一下,确实挺有意思。这里记录一下在Python中如何去使用chatGPT。本篇文章的实现100%基于
- 显示大图和隐藏大图的js代码:<script type="text/javascript"> &n
- 目录简介图形加载和说明图形的灰度灰度图像的压缩原始图像的压缩总结简介本文将会以图表的形式为大家讲解怎么在NumPy中进行多维数据的线性代数运
- 目标函数编码方式本程序采用的是二进制编码精确到小数点后五位,经过计算可知对于 其编码长度为18,对于 其编码长度为15,因此每个基于的长
- ENV:[root@centos7 ~]# uname -r3.10.0-514.el7.x86_64[root@centos7 ~]# c
- 首先,我想说下写代码的一些习惯,第一,任何可配置的参数或变量都要写到一个config文件中。第二,代码中一定要有日志记录和完善的报错并记录报
- 本文实例为大家分享了python七夕浪漫表白的具体代码,供大家参考,具体内容如下from turtle import *from time
- 1.为什么要使用域名访问部署在Istio中的程序我们在Istio中部署的程序一定不止有一个,前面我们已经在Istio中部署了Httpbin、
- 写接口case时,有时需要对cae做一些共性的操作,最典型的场景如:获取case执行时间、打印log等。有没有一种办法来集中处理共性操作从而
- 回文利用python 自带的翻转 函数 reversed()def is_plalindrome(string): return
- part 1最近在学习go自带的rpc,看完了一遍想着自己实现一个codec,也就是自定义消息的序列化和反序列化。消息的序列化和反序列化涉及
- 以前从来没有写过特别多的代码,这次在阅读论文的时候跑别人的代码的时候出现了很多import的问题,这里我想跟大家分享一下,我在Ubuntu系
- 背景开发项目时应学会站在巨人的肩膀上,即有效利用开发组件进行或工具提升自己的研发效率对于较简单的单体函数而言,只需要依赖原生的SDK即可完成
- 并发安全和锁有时候在Go代码中可能会存在多个goroutine同时操作一个资源(临界区),这种情况会发生竞态问题(数据竞态)。类比现实生活中
- C# 连接oracle数据库常用的三种方法有三种:一、Oracle.ManagedDataAccess.dll:Oracle官方提供的ora
- 平时我们获取事件对象一般写法如下:function getEvent(event) { return event
- 一、 for 循环根据变量赋值的次数进行循环for item in ["tom","bob",&qu
- 本文实例为大家分享了python自动发送报警监控邮件 的具体代码,供大家参考,具体内容如下因为有一些日常任务需要每日检查日否执行正确,所以需
- 本文实例讲述了基于python编写的微博应用,分享给大家供大家参考。具体如下:在编写自己的微博应用之前,先要到weibo开放平台申请应用的公
- 我们一般在调试程序的时候,有些操作会莫名地失败,又没有错误消息提示,特别是在执行数据库操作的时候,明明执行过去了,可就是数据库里没有记录变动