How can I update a nested set tree structure?
我看过在 MySQL 中管理分层数据,但它实际上只涉及在嵌套集模型中添加和删除节点。
我需要能够移动带子节点和不带子节点的节点。
我该怎么做?
这是一个解决方案,让您只需一个输入参数即可将节点移动到树中的任何位置 - 节点的新左侧位置 (newpos)。这种方法不能在没有子节点的情况下移动节点,但我很想知道您的用例。
基本上分为三组:
- 为子树创建新空间。
- 将子树移动到这个空间。
- 删除子树腾出的旧空间。
在psuedo-sql中是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 | // * -- create new space for subtree * UPDATE tags SET lpos = lpos + :width WHERE lpos >= :newpos * UPDATE tags SET rpos = rpos + :width WHERE rpos >= :newpos * * -- move subtree into new space * UPDATE tags SET lpos = lpos + :distance, rpos = rpos + :distance * WHERE lpos >= :tmppos AND rpos < :tmppos + :width * * -- remove old space vacated by subtree * UPDATE tags SET lpos = lpos - :width WHERE lpos > :oldrpos * UPDATE tags SET rpos = rpos - :width WHERE rpos > :oldrpos */ |
:distance 变量是新旧位置之间的距离, :width 是子树的大小, :tmppos 用于跟踪更新期间移动的子树。这些变量定义为:
1 2 3 4 5 6 7 8 9 10 | // calculate POSITION adjustment VARIABLES INT width = node.getRpos() - node.getLpos() + 1; INT distance = newpos - node.getLpos(); INT tmppos = node.getLpos(); // backwards movement must account FOR NEW SPACE IF (distance < 0) { distance -= width; tmppos += width; } |
有关完整的代码示例,请参阅我的博客
https://rogerkeays.com/how-to-move-a-node-in-nested-sets-with-sql
如果你喜欢这个解决方案,请点赞。
与子节点一起移动:
在经典的嵌套集合中,a€?lefta€?和一个€?righta€?值都在 0..n*2 个值的连续块中,会有一系列行移动 a€?xa€?左边的地方还是 a€?xa€?当子树移动时,放在右边,哪里 a€?xa€?是移动的左/右值的数量。例如。
1 2 3 4 5 | A: 1,6 B: 2,3 C: 4,5 D: 7,8 E: 9,10 |
如果你移动了€?Aa€?与后代之间的€?Da€?和 a€?Ea€?,a€?Aa€? 右侧的所有内容?但是在a€的左边?Ea€?需要将其左/右索引减少 6(具有后代的 a€?Aa€? 的大小):
1 2 3 4 5 6 7 8 9 10 11 | UPDATE things SET nsl=nsl+( IF nsl BETWEEN 1 AND 6 THEN 6 -- A-C go forward 6 ELSE -6 -- D goes back 6 ), nsr=nsr+( -- same again IF nsl BETWEEN 1 AND 6 THEN 6 ELSE -6 ) WHERE nsl BETWEEN 1 AND 6 -- select A-C OR nsl BETWEEN 7 AND 8 -- select D |
在没有子节点的情况下移动更复杂。被包含的节点必须往回走一,被移除的节点之后的节点都必须往回走二,那么新插入点之后的节点必须往前走两以腾出空间。
虽然您可以使用与上述相同的样式来执行此操作,但它开始变得非常混乱,您可能想考虑替代方法,例如手动重写所有左/右值或使用不同的模式类型这些类型的操作更简单,例如完整的祖先-后代邻接关系。
嵌套集设计不是对树进行这种更改的好选择。当您移动节点时重新计算右/左数字真的很复杂。
邻接表是移动子树最简单的树设计:
1 2 3 | UPDATE TreeTable SET parent = $newparent WHERE id = 123; |
Path Enumeration 设计还可以轻松地重新定位节点及其子节点:
1 2 3 | UPDATE TreeTable SET path = REPLACE(path, 'A/B/C/', 'A/D/F/') -- MySQL function WHERE path LIKE 'A/B/C/%'; |
考虑移动一个节点相当于删除该节点及其所有子节点(如果有),并在新位置插入该节点及其子节点(如果有)。
现在重新阅读技术文章,计算出执行删除和插入操作后整个表的外观,您会发现执行相同操作的更新。