Move node in nested set

后端 未结 13 1023
孤街浪徒
孤街浪徒 2020-12-07 15:06

I\'d need a MySQL query that moves a node and all its children within a nested set. I found this site, but that function just seems so illogical - there\'s no universe

13条回答
  •  南笙
    南笙 (楼主)
    2020-12-07 15:37

    There are many answers already, but I feel like mine can be useful for someone. Based on answer of Roger Keays (thank you very much!), I wrote stored procedures for mySQL database:

    -- to move target before specified node
    CREATE DEFINER=`root`@`%` PROCEDURE `move_before`(IN target_id int, before_id int)
    BEGIN
        SELECT @new_pos := lft FROM dirs WHERE  id = before_id; 
        CALL  move(target_id, @new_pos);
    END
    
    -- to move target after specified node
    CREATE DEFINER=`root`@`%` PROCEDURE `move_after`(IN target_id int, after_id int)
    BEGIN
        SELECT @new_pos := rgt + 1 FROM dirs WHERE  id = after_id;
        CALL  move(target_id, @new_pos);
    END
    
    -- to move target to the specified node
    CREATE DEFINER=`root`@`%` PROCEDURE `move_in`(IN target_id int, parent_id int)
    BEGIN
        SELECT @new_pos := rgt FROM dirs WHERE  id = parent_id;
        CALL  move(target_id, @new_pos);
    END
    
    --main procedure to move target before position 
    CREATE DEFINER=`root`@`%` PROCEDURE `move`(in target_id int, in  new_pos int)
    BEGIN
    
        SELECT @oldlft :=  lft, @oldrgt :=  rgt 
        FROM dirs 
        WHERE target_id =  id;
    
        SET @width := @oldrgt - @oldlft +1;
        SET @distance :=  new_pos - @oldlft;
        SET @tmppos := @oldlft;
    
        IF (@distance <0)
        THEN
            SELECT @distance := @distance - @width;
            SELECT @tmppos := @tmppos + @width;
        END IF;
    
        -- create new space for subtree
        UPDATE dirs SET lft = lft + @width WHERE lft >=  new_pos;
        UPDATE dirs SET rgt = rgt + @width WHERE rgt >=  new_pos;
    
        -- move subtree into new space
        UPDATE dirs SET lft = lft + @distance, rgt = rgt + @distance
            WHERE lft >= @tmppos AND rgt < @tmppos + @width;
    
        -- remove old space vacated by subtree
        UPDATE dirs SET lft = lft - @width WHERE lft > @oldrgt;
        UPDATE dirs SET rgt = rgt - @width WHERE rgt > @oldrgt;
    
    END
    

提交回复
热议问题