没有合适的资源?快使用搜索试试~ 我知道了~
managing-hierarchical-data-in-mysql 分层数据管理和树状结构
资源详情
资源评论
资源推荐
MYSQL 中分层数据的管理
MYSQL 中分层数据的管理
By Mike Hillyer
引言
大多数用户都曾在数据库中处理过分层数据(hierarchical data),认为分层数据的管理不
是关系数据库的目的。之所以这么认为,是因为关系数据库中的表没有层次关系,只是简单
的平面化的列表;而分层数据具有父-子关系,显然关系数据库中的表不能自然地表现出其
分层的特性。
我们认为,分层数据是每项只有一个父项和零个或多个子项(根项除外,根项没有父项)的
数据集合。分层数据存在于许多基于数据库的应用程序中,包括论坛和邮件列表中的分类、
商业组织图表、内容管理系统的分类、产品分类。我们打算使用下面一个虚构的电子商店的
产品分类:
这些分类层次与上面提到的一些例子中的分类层次是相类似的。在本文中我们将从传统的邻
接表(adjacency list)模型出发,阐述 2 种在 MySQL 中处理分层数据的模型。
邻接表模型
上述例子的分类数据将被存储在下面的数据表中(我给出了全部的数据表创建、数据插入的
第 1 页/总 16 页
MYSQL 中分层数据的管理
代码,你可以跟着做):
CREATE TABLE category(
category_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
parent INT DEFAULT NULL);
INSERT INTO category
VALUES(1,'ELECTRONICS',NULL),(2,'TELEVISIONS',1),(3,'TUBE',2),
(4,'LCD',2),(5,'PLASMA',2),(6,'PORTABLE ELECTRONICS',1),
(7,'MP3 PLAYERS',6),(8,'FLASH',7),
(9,'CD PLAYERS',6),(10,'2 WAY RADIOS',6);
SELECT * FROM category ORDER BY category_id;
+-------------+----------------------+--------+
| category_id | name | parent |
+-------------+----------------------+--------+
| 1 | ELECTRONICS | NULL |
| 2 | TELEVISIONS | 1 |
| 3 | TUBE | 2 |
| 4 | LCD | 2 |
| 5 | PLASMA | 2 |
| 6 | PORTABLE ELECTRONICS | 1 |
| 7 | MP3 PLAYERS | 6 |
| 8 | FLASH | 7 |
| 9 | CD PLAYERS | 6 |
| 10 | 2 WAY RADIOS | 6 |
+-------------+----------------------+--------+
10 rows in set (0.00 sec)
在邻接表模型中,数据表中的每项包含了指向其父项的指示器。在此例中,最上层项的父项
为空值(NULL)。邻接表模型的优势在于它很简单,可以很容易地看出 FLASH 是 MP3 PLAYERS
的子项,哪个是 portable electronics 的子项,哪个是 electronics 的子项。虽然,在客
户端编码中邻接表模型处理起来也相当的简单,但是如果是纯 SQL 编码的话,该模型会有很
多问题。
检索整树
通常在处理分层数据时首要的任务是,以某种缩进形式来呈现一棵完整的树。为此,在纯
SQL 编码中通常的做法是使用自连接(self-join):
SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
LEFT JOIN category AS t4 ON t4.parent = t3.category_id
WHERE t1.name = 'ELECTRONICS';
+-------------+----------------------+--------------+-------+
| lev1 | lev2 | lev3 | lev4 |
+-------------+----------------------+--------------+-------+
| ELECTRONICS | TELEVISIONS | TUBE | NULL |
| ELECTRONICS | TELEVISIONS | LCD | NULL |
| ELECTRONICS | TELEVISIONS | PLASMA | NULL |
第 2 页/总 16 页
MYSQL 中分层数据的管理
| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS | FLASH |
| ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS | NULL |
| ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL |
+-------------+----------------------+--------------+-------+
6 rows in set (0.00 sec)
检索所有叶子节点
我们可以用左连接(LEFT JOIN)来检索出树中所有叶子节点(没有孩子节点的节点):
SELECT t1.name FROM
category AS t1 LEFT JOIN category as t2
ON t1.category_id = t2.parent
WHERE t2.category_id IS NULL;
+--------------+
| name |
+--------------+
| TUBE |
| LCD |
| PLASMA |
| FLASH |
| CD PLAYERS |
| 2 WAY RADIOS |
+--------------+
检索单一路径
通过自连接,我们也可以检索出单一路径:
SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
LEFT JOIN category AS t4 ON t4.parent = t3.category_id
WHERE t1.name = 'ELECTRONICS' AND t4.name = 'FLASH';
+-------------+----------------------+-------------+-------+
| lev1 | lev2 | lev3 | lev4 |
+-------------+----------------------+-------------+-------+
| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS | FLASH |
+-------------+----------------------+-------------+-------+
1 row in set (0.01 sec)
这种方法的主要局限是你需要为每层数据添加一个自连接,随着层次的增加,自连接变得越
来越复杂,检索的性能自然而然的也就下降了。
邻接表模型的局限性
用纯 SQL 编码实现邻接表模型有一定的难度。在我们检索某分类的路径之前,我们需要知道
第 3 页/总 16 页
MYSQL 中分层数据的管理
该分类所在的层次。另外,我们在删除节点的时候要特别小心,因为潜在的可能会孤立一棵
子树(当删除 portable electronics 分类时,所有他的子分类都成了孤儿)。部分局限性
可以通过使用客户端代码或者存储过程来解决,我们可以从树的底部开始向上迭代来获得一
颗树或者单一路径,我们也可以在删除节点的时候使其子节点指向一个新的父节点,来防止
孤立子树的产生。
嵌套集合(Nested Set)模型
我想在这篇文章中重点阐述一种不同的方法,俗称为嵌套集合模型。在嵌套集合模型中,我
们将以一种新的方式来看待我们的分层数据,不再是线与点了,而是嵌套容器。我试着以嵌
套容器的方式画出了 electronics 分类图:
从上图可以看出我们依旧保持了数据的层次,父分类包围了其子分类。在数据表中,我们通
过使用表示节点的嵌套关系的左值(left value)和右值(right value)来表现嵌套集合模型
中数据的分层特性:
CREATE TABLE nested_category (
category_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20) NOT NULL,
lft INT NOT NULL,
rgt INT NOT NULL
);
INSERT INTO nested_category
VALUES(1,'ELECTRONICS',1,20),(2,'TELEVISIONS',2,9),(3,'TUBE',3,4),
(4,'LCD',5,6),(5,'PLASMA',7,8),(6,'PORTABLE ELECTRONICS',10,19),
(7,'MP3 PLAYERS',11,14),(8,'FLASH',12,13),
(9,'CD PLAYERS',15,16),(10,'2 WAY RADIOS',17,18);
SELECT * FROM nested_category ORDER BY category_id;
+-------------+----------------------+-----+-----+
| category_id | name | lft | rgt |
+-------------+----------------------+-----+-----+
| 1 | ELECTRONICS | 1 | 20 |
| 2 | TELEVISIONS | 2 | 9 |
| 3 | TUBE | 3 | 4 |
| 4 | LCD | 5 | 6 |
| 5 | PLASMA | 7 | 8 |
| 6 | PORTABLE ELECTRONICS | 10 | 19 |
第 4 页/总 16 页
剩余15页未读,继续阅读
weigecdn
- 粉丝: 4
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- F103-霸道开发板2.8寸电阻触摸屏例程.rar
- Google(高德)地图瓦片python代码下载
- Python实现输出杨辉三角形
- polsarpro官方教程、操作说明 PolSARpro v5.0 Software Training Course
- STM32 TouchGFX的使用二图片显示
- buildx镜像文件,也可以通过网上其他方式获取
- 【中级软件设计师】上午题12-软件工程(2):单元测试、黑盒测试、白盒测试、软件运行与维护
- 免费计算机毕业设计-医院住院管理系统的设计与实现(包含代码+论文)
- tt100k数据转换yolo格式
- 免费计算机毕业设计-学生在线网络考试系统的设计与实现(包含论文+源码)
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0