我遇到嵌套集模型的问题,使用MySQL。 我可以插入,删除,将子树移动到另一个父节点,一切正常。
但我无法弄清楚如何订购兄弟姐妹。例如,我有这些兄弟姐妹:
A,B,C,D,E
我想在D之后移动B,获得这个:
A,C,D,B,E
我发现大量的存储过程用于插入,删除等,但没有一个存储过程来订购兄弟姐妹。我发现的唯一一个是交换兄弟姐妹的程序,但这不是我想要达到的目的。
我试着写自己的,但它似乎很复杂,并不适用于所有情况。
如果你知道如何在他的一个兄弟姐妹之前或之后移动一个节点,我们将不胜感激。
答案 0 :(得分:5)
所以...我重写了所有内容,这里有一个存储过程,可以很好地在他的一个兄弟姐妹之后移动一个节点。如果我们想将节点移动到第一个位置,只需传递父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 ;
也许这不是我们见过的最美丽的代码片段,但它工作得很好,并且可能比任何类型的排序算法都更有效率。例如。
答案 1 :(得分:0)
我发现,在使用触发器处理嵌套集时,最好是:
特别是对于您的问题,如果我做对了,您将使用存储过程逐个移动节点。它与更改节点的父节点没有太大区别:找到它的新lft / rgt索引并相应地向左或向右移动它(及其子节点)。如果它向右移动,请不要忘记偏移lft / rgt值。
顺便说一句,我怀疑你只是开始确定你需要解决的潜在问题。在我的经验中,使用单个更新的节点排列是最棘手的,例如:
A - B - C
D - E - F
要:
B - E - C
A - D - F