您好,欢迎访问一九零五行业门户网

树状数据结构存储方式(CUD 篇)

前文简单介绍了嵌套集合的数据模型,以及查询的方法,传送门: 树状数据结构存储方式 (查询篇)
create
在嵌套集合模型中,每个数据其实就是一个节点 (node),而每个节点占用 2 个位值,比如我们先新增一个 smartphones 一级节点开始。
insert into `categories` (`title`, `lft`, `rgt`) values('smartphones', 1, 2);
smartphones 作为一个主节点 (root),它的 lft 必定为 1,而 rgt 的值,会随着其集合内的子元素增加而增加。
现在,我们希望在 smartphones 内,添加一个子元素 android。借助 mysql 的存储过程。
lock table categories write;select @root_left := lft from categories where title = 'smartphones';update categories set rgt = rgt + 2 where rgt > @root_left;update categories set lft = lft + 2 where lft > @root_left;insert into categories (title, lft, rgt) values('android', @root_left + 1, @root_left + 2);unlock tables;select `title`, `lft`, `rgt` from `categories`;+-------------+-----+-----+| title | lft | rgt |+-------------+-----+-----+| smartphones | 1 | 4 || android | 2 | 3 |+-------------+-----+-----+
我们再尝试往 android 内添加一个子元素 小米:
lock table categories write;select @root_left := lft from categories where title = 'android';update categories set rgt = rgt + 2 where rgt > @root_left;update categories set lft = lft + 2 where lft > @root_left;insert into categories (title, lft, rgt) values('小米', @root_left + 1, @root_left + 2);unlock tables;select `title`, `lft`, `rgt` from `categories`;+-------------+-----+-----+| title | lft | rgt |+-------------+-----+-----+| smartphones | 1 | 6 || android | 2 | 5 || 小米 | 3 | 4 |+-------------+-----+-----+
这时候,我们再尝试往 smartphones 内添加一个子元素 ios,在前面,我们已经在里面添加了一个 android 元素,所以这里要调整一下存储过程,将 ios 插入到 android 的右边
lock table categories write;select @next_right := rgt from categories where title = 'android';update categories set rgt = rgt + 2 where rgt > @next_right;update categories set lft = lft + 2 where lft > @next_right;insert into categories(title, lft, rgt) values('ios', @next_right + 1, @next_right + 2);unlock tables;select `title`, `lft`, `rgt` from `categories`;+-------------+-----+-----+| title | lft | rgt |+-------------+-----+-----+| smartphones | 1 | 8 || android | 2 | 5 || 小米 | 3 | 4 || ios | 6 | 7 |+-------------+-----+-----+
delete
删除节点时,其实可以看做是新增节点的逆过程,我们引入一个宽度,来衡量节点的宽段,其表示为: rgt - lft + 1 所以我们可以这样写存储过程:
lock table categories write;select @delete_left := lft, @delete_right := rgt, @delete_width := rgt - lft + 1from categories where title = 'android';delete from categories where lft between @delete_left and @delete_right;update categories set rgt = rgt - @delete_width where rgt > @delete_right;update categories set lft = lft - @delete_width where lft > @delete_right;unlock tables;select `title`, `lft`, `rgt` from `categories`;+-------------+-----+-----+| title | lft | rgt |+-------------+-----+-----+| smartphones | 1 | 4 || ios | 2 | 3 |+-------------+-----+-----+
update
移动节点,是一个比较复杂的过程,例如下图,macos 应该归类到 unix 分类下。
要实现节点的移动,需要三步:
1、将要移动的节点摘出来
2、重新编排 lft 和 rgt 参数
3、将节点移动到指定位置
lock table categories write;-- 将要移动的节点摘出来,并且重新边篇 lft 和 rgtselect @move_left := lft , @move_right := rgt, @move_width := rgt - lft + 1from categories where title = 'macos';update categories set rgt = -rgt where lft between @move_left and @move_right;update categories set lft = -lft where lft between @move_left and @move_right;update categories set rgt = rgt - @move_width where rgt > @move_right;update categories set lft = lft - @move_width where lft > @move_right;-- 将节点放到 unix 节点里select @root_left := lft from categories where title = 'unix';update categories set rgt = rgt + @move_width where rgt > @root_left;update categories set lft = lft + @move_width where lft > @root_left;-- update categories set lft = @root_left + 1 where lft between -@move_right and -@move_left;update categories set rgt = @root_left + 2 where rgt between -@move_right and -@move_left;unlock tables;
总结
其实 sql 中的嵌套集合的数据模型已经提出很久了,也有很多包已经实现了这个功能,比如 laravel-nestedset 或者 django-mptt
对于生产使用中,肯定是没有这么简单的表结构设计,或者甚至别的优化,比如一种称为闭合表的数据模型,这个应该会在本系列文章中介绍给大家。
以上就是树状数据结构存储方式(cud 篇)的详细内容。
其它类似信息

推荐信息