关系型数据库如何存储树形结构?
方法一 父节点表示法
每一个节点持有父节点的引用。为了更好的处理森林,抽象一个不存在的 0 节点,森林中所有树挂在改节点下,将森林转换为一颗树来处理。
此方法结构简单,更新也简单,但是在查询子孙节点时,效率低下.
方法二 路径表示法
在方法一的基础上,添加 path_key(search_key)字段,该字段存储从根节点到节点的标识路径,这里依然抽象一个不存在的 0 节点。
插入数据
查询数据
查询森林的根节点
SELECT * FROM node2 WHERE p_id = 0 AND search_key LIKE '0-%' AND level = 0;
查询节点 A 的所有子孙节点
SELECT * FROM node2 WHERE search_key LIKE '{A.search_key}%';
SELECT * FROM node2 WHERE search_key LIKE '0-1-%';
更新数据(当插入一定量叶子结点时)
例如,更新节点 C 的权重
UPDATE node2,(SELECT sum(num) AS sum FROM node2 WHERE search_key LIKE '0-1-3-%') rt SET num = rt.sum WHERE id=3;
有节点权重累加时,将所有父辈权重再加 1,只需要将该节点的 search_key 以'-' 切分,得到的就是所有父辈的 id(0 除外)。例如,将节点 D 的权重+1,这里使用 where locate,实际更好是先将 search_key split 之后使用 where in 查询
UPDATE node2,(SELECT search_key FROM node2 WHERE id = 4) rt SET num=num+1 WHERE locate(id,rt.search_key);
删除某个节点,比如删除 B 节点
假设删除节点子孙全部清理
DELETE FROM node2 WHERE search_key LIKE '0-1-2%';
方法 3 前序遍历法
给节点分配左右值,第一次到达该节点时,设置左值,第二次到达该节点,设置右值,每走一步,序号加 1
这里加入了一个 tree_id 字段,用来保证对一棵树内的更新操作,不会影响到别的树,有利于提高效率。
插入数据(用 tree_id 判断是否同一棵树)
仔细看可以发现,在已有一个节点下 append 一个节点 M 的话,M 的左右值应该连续的,按照先序遍历的顺序,只需要将走在其后的节点的左右值分别+2,并且 M 节点的父节点的右值必然也要+2。
查询数据
# 查询子节点
select * from node3 where lft >lft && rgt < rgt
# 查询父节点
select * from node3 where lft < lft && rgt >rgt
版权声明: 本文为 InfoQ 作者【王博】的原创文章。
原文链接:【http://xie.infoq.cn/article/af8417e463d041740fab02f9d】。文章转载请联系作者。
评论