前序遍历(nested model)树算法笔记


环境说明:
db
mysql 5.5.32-log

tools: sqlyog (可选)



准备 sql  语句

/*declare table construct   定义表结构   lft左值  rgt右值  removed移动标志位*/
DROP TABLE IF EXISTS `nested_category`;

CREATE TABLE `nested_category` (
  `title` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
  `parent` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  `lft` int(11) DEFAULT NULL,
  `rgt` int(11) DEFAULT NULL,
  `weight` int(11) DEFAULT NULL,
  `cn_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  `removed` tinyint(4) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


/*Data for the table `nested_category`  导入初始数据 */

LOCK TABLES `nested_category` WRITE;

insert  into `nested_category`(`title`,`parent`,`lft`,`rgt`,`weight`,`cn_name`,`removed`) values ('Banana','Yello',8,9,NULL,'香蕉',0),('Beef','Meat',13,14,NULL,'牛肉',0),('Cherry','Red',4,5,NULL,'樱桃',0),('Food',NULL,1,18,NULL,'食物',0),('Fruit','Food',2,11,NULL,'水果 ',0),('Meat','Food',12,17,NULL,'肉',0),('Pork','Meat',15,16,NULL,'猪肉',0),('Red','Fruit',3,6,NULL,'红',0),('Yello','Fruit',7,10,NULL,'黄色',0);

UNLOCK TABLES;







备份与恢复

#复制表结构
CREATE TABLE `nested_category_origi` LIKE `nested_category`;

#复制表结构及数据
CREATE TABLE `nested_category_origi` SELECT * FROM `nested_category`;
#----------------恢复 begin ---------------
SET autocommit=0;
START TRANSACTION;

/*
#去掉外外键约束  当自关联时有用
UPDATE `nested_category`
SET `parent` = NULL;
*/
 
DELETE FROM `nested_category`;

INSERT INTO `nested_category`
(     `title`,
        `parent`,
        `lft`,
        `rgt`,
        `weight`,
        `cn_name`,
        `removed`
)
(
     SELECT
       `title`,
       `parent`,
       `lft`,
       `rgt`,
       `weight`,
       `cn_name`,
       `removed`
     FROM `nested_category_origi`
     #一定要有这个排序,要不外键依赖有问题
     ORDER BY lft ASC
)
ON DUPLICATE KEY UPDATE
     parent = VALUES(parent),
     lft = VALUES(lft),
     rgt = VALUES(rgt),
     weight = VALUES(weight),
     cn_name = VALUES(cn_name),
     removed = VALUES(removed)
;

COMMIT;
#ROLLBACK;
SET autocommit=1;
#----------------恢复 end---------------



数据结构及算法原理:

    我们先把树按照水平方式摆开 从根节点开始(“Food”),然后他的左边写上1 然后按照树的顺序(从上到下)给“Fruit”的左边写上2。这样,你沿着树的边界走啊走(这就是“遍历”),然后同时在每个节点的左边和右边写上数字 最后,我们回到了根节点“Food”在右边写上18。下面是标上了数字的树,同时把遍历的顺序用箭头标出来了

遍历的次序是:
1 从树的根结点出发,先访问结点左值。
2   递归子结点左值。
3 遍历到树叶结点(rgt-lft=2)时,访问本结点的右值
4 查看是否有兄弟结点,若有按 2,3操作
5 递归退回父结点,若有未访问的子树时,按2,3,4 ,否则就访问结点的右值,并一直回退至根结点的右值,整个过程结束。

结点间的关系  比如说 a结点与b结点有4种关系
a左b右  ->  a.rgt<b.lft
a右b左  ->  b.rgt<a.lft
a祖b孙  ->  b.lft between a.lft and a.rgt 
b祖a孙  ->  a.lft between b.lft and b.rgt
简单的说就是: 左路结点.rgt<右结点.lft    |      子孙结点.lft between  祖先结点.lft and 祖先结点.rgt

 



    我们称这些数字为左值和右值(如,“Food”的左值是1,右值是18)正如你所见,这些数字按时了每个节点之间的关系因为“Red”有3和6两个值,所以,它是有拥有1-18值的“Food”节点的后续。同样的,我们可以推断所有左值大于2并且右值小于11的节点,都是有2-11的“Fruit” 节点的后续这样,树的结构就通过左值和右值储存下来了。这种数遍整棵树算节点的方法叫做“改进前序遍历树”算法

表数据如下设计:





核心算法SQL语句




下面是比较常用的查询方法


#每个结点与祖先或自己结点的连接关系  这个很关键
SELECT node.title,node.lft,node.rgt, (parent.title) AS parent_title,parent.lft AS parent_lft,parent.rgt AS parent_rgt
FROM nested_category node, nested_category parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
order by node.lft asc ;




#前序查询树结点,按title分组,lft排序,node.title出现次数就是本结点树深度
SELECT node.title,MAX(node.lft) AS lft,MAX(node.rgt) AS rgt, MAX(parent.title) AS parent_title,MAX(parent.lft) AS parent_lft,MAX(parent.rgt) AS parent_rgt,COUNT(1) AS deepth
FROM nested_category node, nested_category parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
GROUP BY node.title
ORDER BY node.lft ASC;




#查某个子树的结构 指定一个父结点
SELECT node.title,MAX(node.lft) AS lft,MAX(node.rgt) AS rgt, MAX(parent.title) AS parent_title,MAX(parent.lft) AS parent_lft,MAX(parent.rgt) AS parent_rgt
FROM nested_category node, nested_category parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt AND parent.`title`='Food'
GROUP BY node.title
ORDER BY node.lft;





#查找祖先
SELECT parent.title,parent.cn_name,parent.lft
FROM nested_category node, nested_category parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
       AND node.title = 'Banana'
ORDER BY parent.lft ASC





插入逻辑: 在父结点下新增一个结点
1 计算父结点右值( @currnt_right)
2 修改调整相关结点自增2(一个结点的子树宽度就是 rgt-lft+1=2)    when lft> @currnt_right then set lft=lft+2    when rgt>= @currnt_right then set rgt=rgt+2
3 插入新记录行  set lft= @currnt_right  set rgt= @currnt_right+1
4 修改父结点右值自增2  set parent.rgt= parent.rgt+2


#  ---------插入结点  begin ------------------------

SET autocommit=0;
START TRANSACTION;

#表加写锁
LOCK TABLES nested_category WRITE;

#要插入的父结点title
SET @current_title = 'Red';
SET @new_titile='Lichee',@new_cn_name='荔枝';
#set @new_titile='Tomato',@new_cn_name='西红柿';

#设置当前结点右值变量
SELECT @currnt_right:=rgt FROM nested_category WHERE title = @current_title;


#更新右值比@currnt_right大的,全部+2
UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @currnt_right;

#更新右值比@currnt_right大的,全部+2
UPDATE nested_category SET lft = lft + 2 WHERE lft > @currnt_right;

#插入新记录,左传=@currnt_right(原父结点的右值)   右值=@currnt_right+1
INSERT INTO `nested_category`
(`title`,`parent`,`lft`,`rgt`,`weight`,`cn_name`)
VALUES (@new_titile,@current_title,@currnt_right,(@currnt_right+1),NULL,@new_cn_name);

#原父结点的右值自增2
UPDATE nested_category SET rgt = (@currnt_right+2) WHERE rgt = @currnt_right;

#释放表锁
UNLOCK TABLES;

#commit;
ROLLBACK;
SET autocommit=1;

#  ---------插入结点  end ------------------------








删除操作逻辑:删除是删除指定结点及其下属子树
1 用变量保存待删除结点的左(@myLeft)右值(@myRight),及计算出子树的宽度 @myWidth=rgt-lft+1 .
2 删除本结点及下属子结点 lft between @myLeft and @myRight
3 调整余下相关结点,自增子树宽度.   when lft>@myRight then set lft=lft+@myWidth     when rgt>=@myRight  then set rgt=rgt+@myWidth


#  ---------删除结点  begin ------------------------

SET autocommit=0;
START TRANSACTION;


#表加写锁
LOCK TABLES nested_category WRITE;

SET @current_title='Lichee';

SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1
  FROM nested_category
WHERE title = @current_title;

#删除本结点及子树结点
DELETE FROM nested_category WHERE lft BETWEEN @myLeft AND @myRight;

UPDATE nested_category SET rgt = rgt - @myWidth WHERE rgt > @myRight;
UPDATE nested_category SET lft = lft - @myWidth WHERE lft > @myRight;


#释放表锁
UNLOCK TABLES;

#commit;
ROLLBACK;
SET autocommit=1;

#  ---------删除结点  end ------------------------








移动一棵子树,从本质来讲就是删除旧子树,在目标结点下追加新子树(新子树内部结构与旧子树相同)。移动后source与target是父子关系(source.lft between target.lft and target.rgt)
这里的子树,特例是子树只有一个结点,就等同于删除一个结点,在目标结点下面追加一个新结点,跟上面的操作是一样的 
上面的新增与删除都是子树的特例(只有一个结点的树默认宽度就是2)
子树操作中宽度(就是子树根结点的宽度)这个概念很重要逻辑:  node_width=rgt-lft+1     (树枝结点宽度>2   树叶结点宽度==2)
移动的偏移量(target.rgt-source.lft),移动有三种情况,左移右,右移左,子移祖。子树内部结构不变,但是全部子树内的结点lft,rgt都要修改加上偏移量。
操作逻辑:
1 计算子树宽度 @sub_tree_width=source.rgt - source.lft + 1
2 修改子树各结点删除标志位为1,假删除 removed=true(默认是false)
3 删除源子树后,剩下树各个结点都要调整(剔除原子树 removed=true)左值右值      when rgt>=source.rgt    then -> set rgt=rgt-@sub_tree_width  ; when lft>=source.rgt    then -> set lft=lft-@sub_tree_widthset lft=lft-@sub_tree_width
4 计算位移偏移量 @shift_diff=target.rgt - source.lft,获取目标结点的右值. (移动后结果是源子树的lft就是目标的rgt ,而子树中各结点lft rgt都要自增偏移量,  rgt>=目标rgt or lft>目标rgt:自增子树的宽度。
5 修改受新增子树后受影响的结点的左值右值   when rgt>=target.rgt     then -> set rgt=rgt+@sub_tree_width  ; when lft>=target.rgt    then -> set lft=lft+@sub_tree_widthlft=lft+@sub_tree_width
6 按偏移量更新原子树(removed=true)的左值右值      when removed=TRUE and (lft between source.lft and source.rgt)     then -> set lft=lft+@shift_diff , rgt=rgt+@shift_diff
7 更新source.parent=target.id  (可选)


#  --------移动子树  begin ------------------------


#表加写锁
LOCK TABLES nested_category WRITE;

SET @source_node_pk='Yello',@target_node_pk='Meat';
SET @sub_tree_width=0,@source_lft=0,@source_rgt=0,@target_new_rgt=0,@shift_diff=0;

SET autocommit=0;
START TRANSACTION;

#1 计算子树宽度 @sub_tree_width=source.rgt - source.lft + 1
SELECT (node.`rgt`-node.`lft`+1),node.`lft`,node.`rgt` INTO @sub_tree_width,@source_lft,@source_rgt
FROM `nested_category` node
WHERE node.`title`=@source_node_pk;

#2 修改子树各结点删除标志位为1,假删除 removed=true(默认是false)
UPDATE `nested_category`
SET removed=TRUE
WHERE lft BETWEEN @source_lft AND @source_rgt;

#3 删除源子树后,剩下树各个结点都要调整(剔除原子树 removed=true)左值右值      when rgt>=source.rgt    then -> set rgt=rgt-@sub_tree_width  ; when lft>=source.rgt    then -> set lft=lft-@sub_tree_width
UPDATE nested_category 
SET rgt = rgt - @sub_tree_width 
WHERE rgt > @source_rgt AND removed=FALSE;

UPDATE nested_category 
SET lft = lft - @sub_tree_width 
WHERE lft > @source_rgt AND removed=FALSE;

#4 计算位移偏移量 @shift_diff=target.rgt - source.lft,获取目标结点的右值. (移动后结果是源子树的lft就是目标的rgt ,而子树中各结点lft rgt都要自增偏移量,  rgt>=目标rgt or lft>目标rgt:自增子树的宽度。
SELECT SUM(CASE title 
       WHEN @source_node_pk THEN -1*lft
       WHEN @target_node_pk THEN rgt
       ELSE 0
       END) INTO @shift_diff
FROM nested_category ;

#目标rgt因为上面删除操作而调整过rgt,重新获取该值
SELECT rgt INTO @target_new_rgt
FROM `nested_category` 
WHERE title=@target_node_pk;


#5 修改受新增子树后受影响的结点的左值右值   when rgt>=target.rgt     then -> set rgt=rgt+@sub_tree_width  ; when lft>=target.rgt    then -> set lft=lft+@sub_tree_width
UPDATE nested_category 
SET rgt=rgt+@sub_tree_width
WHERE rgt >= @target_new_rgt  AND removed=FALSE;

UPDATE nested_category 
SET lft=(lft+@sub_tree_width)
WHERE lft > @target_new_rgt AND removed=FALSE;


#6 按偏移量更新原子树(removed=true)的左值右值      when removed=TRUE and (lft between source.lft and source.rgt)     then -> set lft=lft+@shift_diff , rgt=rgt+@shift_diff
UPDATE nested_category 
SET lft=lft+@shift_diff,
    rgt=rgt+@shift_diff,
    removed=FALSE
WHERE removed=TRUE;


#7 更新source.parent=target.id  (可选)
UPDATE `nested_category`
SET parent=@target_node_pk
WHERE title=@source_node_pk;


#COMMIT;
ROLLBACK;
SET autocommit=1;

#释放表锁
UNLOCK TABLES;
#  --------移动子树  end ------------------------
#  --------移动子树  begin ------------------------


#表加写锁
LOCK TABLES nested_category WRITE;

SET @source_node_pk='Yello',@target_node_pk='Meat';
SET @sub_tree_width=0,@source_lft=0,@source_rgt=0,@target_new_rgt=0,@shift_diff=0;

SET autocommit=0;
START TRANSACTION;

#1 计算子树宽度 @sub_tree_width=source.rgt - source.lft + 1
SELECT (node.`rgt`-node.`lft`+1),node.`lft`,node.`rgt` INTO @sub_tree_width,@source_lft,@source_rgt
FROM `nested_category` node
WHERE node.`title`=@source_node_pk;

#2 修改子树各结点删除标志位为1,假删除 removed=true(默认是false)
UPDATE `nested_category`
SET removed=TRUE
WHERE lft BETWEEN @source_lft AND @source_rgt;

#3 删除源子树后,剩下树各个结点都要调整(剔除原子树 removed=true)左值右值      when rgt>=source.rgt    then -> set rgt=rgt-@sub_tree_width  ; when lft>=source.rgt    then -> set lft=lft-@sub_tree_width
UPDATE nested_category 
SET rgt = rgt - @sub_tree_width 
WHERE rgt > @source_rgt AND removed=FALSE;

UPDATE nested_category 
SET lft = lft - @sub_tree_width 
WHERE lft > @source_rgt AND removed=FALSE;

#4 计算位移偏移量 @shift_diff=target.rgt - source.lft,获取目标结点的右值. (移动后结果是源子树的lft就是目标的rgt ,而子树中各结点lft rgt都要自增偏移量,  rgt>=目标rgt or lft>目标rgt:自增子树的宽度。
SELECT SUM(CASE title 
       WHEN @source_node_pk THEN -1*lft
       WHEN @target_node_pk THEN rgt
       ELSE 0
       END) INTO @shift_diff
FROM nested_category ;

#目标rgt因为上面删除操作而调整过rgt,重新获取该值
SELECT rgt INTO @target_new_rgt
FROM `nested_category` 
WHERE title=@target_node_pk;


#5 修改受新增子树后受影响的结点的左值右值   when rgt>=target.rgt     then -> set rgt=rgt+@sub_tree_width  ; when lft>=target.rgt    then -> set lft=lft+@sub_tree_width
UPDATE nested_category 
SET rgt=rgt+@sub_tree_width
WHERE rgt >= @target_new_rgt  AND removed=FALSE;

UPDATE nested_category 
SET lft=(lft+@sub_tree_width)
WHERE lft > @target_new_rgt AND removed=FALSE;


#6 按偏移量更新原子树(removed=true)的左值右值      when removed=TRUE and (lft between source.lft and source.rgt)     then -> set lft=lft+@shift_diff , rgt=rgt+@shift_diff
UPDATE nested_category 
SET lft=lft+@shift_diff,
    rgt=rgt+@shift_diff,
    removed=FALSE
WHERE removed=TRUE;


#7 更新source.parent=target.id  (可选)
UPDATE `nested_category`
SET parent=@target_node_pk
WHERE title=@source_node_pk;


#COMMIT;
ROLLBACK;
SET autocommit=1;

#释放表锁
UNLOCK TABLES;
#  --------移动子树  end ------------------------






procedure 存储过程实现方式  上面的语句中,语句很多,而且有很多传值的地方,如果使用JAVA一条一条执行,开发效率慢,逻辑结构复杂。
考虑使用存储过程,相当于对JAVA来讲只是API的调用不需要考虑实现细节,分离修改,procedure只要外部接口不改变,内部修改不会影响到JAVA调用 ,
任何逻辑都内聚(包括业务校验)在过程中,由专门的DB开发人员进行。 但是考虑到有些低版本的5.0.X 5.1.X会不支持存储过程,方案的使用者要充分
考虑这方面的实际情况,如需要就升级到5.5.x版本。

------------------ 新增 结点 begin------------------
DELIMITER $$

USE `school`$$

DROP PROCEDURE IF EXISTS `create_nested_node`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `create_nested_node`(IN current_title VARCHAR(128),IN new_titile VARCHAR(128), IN new_cn_name VARCHAR(128))
BEGIN
     DECLARE currnt_right INT DEFAULT 0;
     DECLARE search_current_num INT DEFAULT 0;
         
     SELECT COUNT(1) INTO search_current_num FROM `nested_category` WHERE title = current_title;
    
     IF search_current_num=0 THEN
        signal SQLSTATE '45000' SET message_text = 'current_title not match at less one recore id db!';
     END IF;
     SET autocommit=0;
     START TRANSACTION;
    
     #设置当前结点右值变量
     SELECT rgt INTO currnt_right FROM nested_category WHERE title = current_title;
     #更新右值比@currnt_right大的,全部+2
     UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > currnt_right;
     #更新右值比@currnt_right大的,全部+2
     UPDATE nested_category SET lft = lft + 2 WHERE lft > currnt_right;
     #插入新记录,左传=@currnt_right(原父结点的右值)   右值=@currnt_right+1
     INSERT INTO `nested_category`
     (`title`,`parent`,`lft`,`rgt`,`weight`,`cn_name`)
     VALUES (new_titile,current_title,currnt_right,(currnt_right+1),NULL,new_cn_name);
     #原父结点的右值自增2
     UPDATE nested_category SET rgt = (currnt_right+2) WHERE rgt = currnt_right;
    
     COMMIT;
     #ROLLBACK;
     SET autocommit=1;
    
    
    END$$

DELIMITER ;
------------------ 新增 结点 end------------------





---------------- 删除结点 begin--------------------------


DELIMITER $$

USE `school`$$

DROP PROCEDURE IF EXISTS `delete_nested_node`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `delete_nested_node`(IN current_title VARCHAR(64))
BEGIN
   
     DECLARE myLeft INT DEFAULT 0;
     DECLARE myRight INT DEFAULT 0;
     DECLARE myWidth INT DEFAULT 0;
     DECLARE search_current_num INT DEFAULT 0;
     SELECT COUNT(1) INTO search_current_num FROM `nested_category` WHERE title = current_title;
    
     IF search_current_num=0 THEN
        signal SQLSTATE '45000' SET message_text = 'can,t delete the record then not exists in db !';
     END IF;
    
     SET autocommit=0;
     START TRANSACTION;
    
    
     SELECT lft, rgt, (rgt-lft+1) INTO myLeft,myRight,myWidth
       FROM nested_category
     WHERE title = current_title;
     #删除本结点及子树结点
     DELETE FROM nested_category WHERE lft BETWEEN myLeft AND myRight;
     UPDATE nested_category SET rgt = rgt - myWidth WHERE rgt > myRight;
     UPDATE nested_category SET lft = lft - myWidth WHERE lft > myRight;
    
     COMMIT;
     #ROLLBACK;
     SET autocommit=1;
   
   
    END$$

DELIMITER ;
---------------- 删除结点 end--------------------------








---------------- 移动结点 begin--------------------------

DELIMITER $$
USE `school`$$
DROP PROCEDURE IF EXISTS `move_sub_tree`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `move_sub_tree`(IN source_node_pk VARCHAR(32),IN target_node_pk VARCHAR(32))
BEGIN
# declare sub_tree_width,source_lft,source_rgt int default 0;
DECLARE sub_tree_width INT DEFAULT 0;
DECLARE source_lft INT DEFAULT 0;
DECLARE source_rgt INT DEFAULT 0;
DECLARE shift_diff INT DEFAULT 0;
DECLARE target_new_rgt INT DEFAULT 0;
DECLARE search_current_num INT DEFAULT 0;
DECLARE search_target_num INT DEFAULT 0;
DECLARE is_inherit_flag BOOLEAN DEFAULT FALSE;
SELECT COUNT(1) INTO search_current_num FROM `nested_category` WHERE title = source_node_pk;
#若源不存在,抛错
IF search_current_num=0 THEN
  signal SQLSTATE '45000' SET message_text = 'source title is not exists renord ID ';
END IF;
SELECT COUNT(1) INTO search_target_num FROM `nested_category` WHERE title = target_node_pk;
#若目标不存在,抛错
IF search_target_num=0 THEN
  signal SQLSTATE '45000' SET message_text = 'target title is not exists renord, ID !';
END IF;
#查看目标结点是否是源结点的子孙
SELECT COUNT(1)=1 INTO is_inherit_flag
FROM (
SELECT parent.title AS title
FROM nested_category node, nested_category parent
WHERE node.lft BETWEEN parent.lft AND parent.rgt
      AND node.title = target_node_pk
ORDER BY parent.lft ASC
) AS _x
WHERE title = source_node_pk;
#若源是目标的祖先,抛锚
IF is_inherit_flag THEN
 signal SQLSTATE '45000' SET message_text='source must not be ancestor of target';
END IF;
SET autocommit=0;
START TRANSACTION;
#1 计算子树宽度 sub_tree_width=source.rgt - source.lft + 1
SELECT (node.`rgt`-node.`lft`+1),node.`lft`,node.`rgt` INTO sub_tree_width,source_lft,source_rgt
FROM `nested_category` node
WHERE node.`title`=source_node_pk;
#2 修改子树各结点删除标志位为1,假删除 removed=true(默认是false)
UPDATE `nested_category`
SET removed=TRUE
WHERE lft BETWEEN source_lft AND source_rgt;
#3 删除源子树后,剩下树各个结点都要调整(剔除原子树 removed=true)左值右值      when rgt>=source.rgt    then -> set rgt=rgt-sub_tree_width  ; when lft>=source.rgt    then -> set lft=lft-sub_tree_width
UPDATE nested_category 
SET rgt = rgt - sub_tree_width 
WHERE rgt > source_rgt AND removed=FALSE;
UPDATE nested_category 
SET lft = lft - sub_tree_width 
WHERE lft > source_rgt AND removed=FALSE;
#4 计算位移偏移量 shift_diff=target.rgt - source.lft,获取目标结点的右值. (移动后结果是源子树的lft就是目标的rgt ,而子树中各结点lft rgt都要自增偏移量,  rgt>=目标rgt or lft>目标rgt:自增子树的宽度。
SELECT SUM(CASE title 
      WHEN source_node_pk THEN -1*lft
      WHEN target_node_pk THEN rgt
      ELSE 0
      END) INTO shift_diff
FROM nested_category ;
#目标rgt因为上面删除操作而调整过rgt,重新获取该值
SELECT rgt INTO target_new_rgt
FROM `nested_category` 
WHERE title=target_node_pk;
#5 修改受新增子树后受影响的结点的左值右值   when rgt>=target.rgt     then -> set rgt=rgt+sub_tree_width  ; when lft>=target.rgt    then -> set lft=lft+sub_tree_width
UPDATE nested_category 
SET rgt=rgt+sub_tree_width
WHERE rgt >= target_new_rgt  AND removed=FALSE;
UPDATE nested_category 
SET lft=(lft+sub_tree_width)
WHERE lft > target_new_rgt AND removed=FALSE;
#6 按偏移量更新原子树(removed=true)的左值右值      when removed=TRUE and (lft between source.lft and source.rgt)     then -> set lft=lft+shift_diff , rgt=rgt+shift_diff
UPDATE nested_category 
SET lft=lft+shift_diff,
   rgt=rgt+shift_diff,
   removed=FALSE
WHERE removed=TRUE;
#7 更新source.parent=target.id  (可选)
UPDATE `nested_category`
SET parent=target_node_pk
WHERE title=source_node_pk;
COMMIT;
#ROLLBACK;
SET autocommit=1;
    END$$
DELIMITER ;

---------------- 移动结点 end--------------------------














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值