mysql - 在嵌套集模型中排序 sibling

标签 mysql siblings nested-set-model

我在使用 MySQL 时遇到了嵌套集模型的问题。 我可以插入、删除子树,将子树移动到另一个父树,一切正常。

但我不知道如何订购 sibling 。例如,我有这些 sibling :

A, B, C, D, E

我想在 D 之后移动 B,得到这个:

A, C, D, B, E

我找到了大量用于插入、删除等的存储过程,但没有一个可以订购 sibling 。我找到的唯一一个是交换 sibling 的程序,但这不是我想要实现的。

我试着自己写一个,但它看起来很复杂,而且并非在所有情况下都有效。

如果您知道如何在他的一个 sibling 之前或之后移动节点,将不胜感激。

最佳答案

所以...我重写了所有内容,这里有一个存储过程,可以很好地在他的一个 sibling 之后移动一个节点。如果我们想将节点移动到第一个位置,只需传递父 id 代替兄弟 id。

DELIMITER |
-- sibling parameter is either :
-- - the sibling id after which we want to put the page
-- - the parent id if we want to put the page on the first position
CREATE PROCEDURE move_after_sibling (IN to_move_id INT(10), IN parent_id INT(10), IN sibling_id INT(10))
LANGUAGE SQL
DETERMINISTIC
BEGIN
    DECLARE to_move_lft INT(10);
    DECLARE to_move_rgt INT(10);
    DECLARE parent_lft INT(10);
    DECLARE parent_rgt INT(10);
    DECLARE sibling_lft INT(10);
    DECLARE sibling_rgt INT(10);

    SET to_move_lft = (SELECT lft FROM pages WHERE id = to_move_id);
    SET to_move_rgt = (SELECT rgt FROM pages WHERE id = to_move_id);
    SET parent_lft = (SELECT lft FROM pages WHERE id = parent_id);
    SET parent_rgt = (SELECT rgt FROM pages WHERE id = parent_id);
    SET sibling_lft = (SELECT lft FROM pages WHERE id = sibling_id);
    SET sibling_rgt = (SELECT rgt FROM pages WHERE id = sibling_id);

    UPDATE pages 
        SET
            lft = 
                CASE 
                    WHEN sibling_id = parent_id THEN
                        CASE
                            WHEN lft BETWEEN parent_lft+1 AND to_move_lft-1 THEN
                                lft + (to_move_rgt - to_move_lft) + 1
                            WHEN lft BETWEEN to_move_lft AND to_move_rgt THEN 
                                lft - (to_move_lft - (parent_lft + 1))
                            ELSE
                                lft
                        END
                    ELSE
                        CASE 
                            WHEN to_move_lft > sibling_lft THEN
                                CASE
                                    WHEN lft BETWEEN sibling_rgt AND to_move_lft-1 THEN
                                        lft + (to_move_rgt - to_move_lft) + 1
                                    WHEN lft BETWEEN to_move_lft AND to_move_rgt THEN 
                                        lft - (to_move_lft - (sibling_rgt + 1))
                                    ELSE
                                        lft
                                END
                            ELSE
                                CASE
                                    WHEN lft BETWEEN to_move_rgt+1 AND sibling_rgt THEN
                                        lft - ((to_move_rgt - to_move_lft) + 1)
                                    WHEN lft BETWEEN to_move_lft AND to_move_rgt THEN 
                                        lft + (sibling_rgt - to_move_rgt)
                                    ELSE
                                        lft
                                END
                        END
                END,
            rgt = 
                CASE 
                    WHEN sibling_id = parent_id THEN
                        CASE
                            WHEN rgt BETWEEN parent_lft+1 AND to_move_lft-1 THEN
                                rgt + (to_move_rgt - to_move_lft) + 1
                            WHEN rgt BETWEEN to_move_lft AND to_move_rgt THEN 
                                rgt - (to_move_lft - (parent_lft + 1))
                            ELSE
                                rgt
                        END
                    ELSE
                        CASE 
                            WHEN to_move_rgt > sibling_lft THEN
                                CASE
                                    WHEN rgt BETWEEN sibling_rgt+1 AND to_move_lft-1 THEN
                                        rgt + (to_move_rgt - to_move_lft) + 1
                                    WHEN rgt BETWEEN to_move_lft AND to_move_rgt THEN 
                                        rgt - (to_move_lft - (sibling_rgt + 1))
                                    ELSE
                                        rgt
                                END
                            ELSE
                                CASE
                                    WHEN rgt BETWEEN to_move_rgt+1 AND sibling_rgt+1 THEN
                                        rgt - ((to_move_rgt - to_move_lft) + 1)
                                    WHEN rgt BETWEEN to_move_lft AND to_move_rgt THEN 
                                        rgt + (sibling_rgt - to_move_rgt)
                                    ELSE
                                        rgt
                                END
                        END
                END
        WHERE lft BETWEEN parent_lft+1 AND parent_rgt;
END
|
DELIMITER ;

也许这不是我们见过的最漂亮的代码,但它运行良好,并且可能比任何类型的排序算法都要高效。

关于mysql - 在嵌套集模型中排序 sibling ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6000762/

相关文章:

php - 从嵌套集模型结构为 Fancytree 创建 JSON

php - 从其他表中选择具有条件规则(计数)的数据

mysql - 无法使用 SSH.Net 隧道连接到 C# 中任何指定的 MySQL 主机

php - yii2中的sql查询

javascript - 访问 SVG 节点的属性

xml - xsl - 最后一个 sibling

css - 用另一个元素的悬停状态改变一个元素的位置

nested-set-model - 在嵌套集中查找最低公共(public)祖先

jquery - 如何使用 AJAX 更新 simple_form 输入字段?

mysql - 如何用sql获取按周滚动的数据集