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 + 1 FROM 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 和 rgt SELECT @move_left := lft , @move_right := rgt, @move_width := rgt - lft + 1 FROM 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 篇)的细致内容,更多请关注ki4网别的相干文章!