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 universeid
or treeid
in a nested set model, and the code itself is just longer than what feels required. The only extra column I've got in the table is parent
.
I couldn't just remove and add the node again since it will loose its ID.
Here is a solution that lets you move a node to any position in the tree, either as a sibling or a child with just a single input parameter - the new left position (newlpos) of the node.
Fundamentally there are three steps:
In psuedo-sql, it looks like this:
The :distance variable is the distance between the new and old positions, the :width is the size of the subtree, and :tmppos is used to keep track of the subtree being moved during the updates. These variables are defined as:
For a complete code example, see my blog at
http://www.ninthavenue.com.au/how-to-move-a-node-in-nested-sets-with-sql
If you like this solution, please up-vote.
See the article in my blog for storing and using hierarchical data in
MySQL
:To move a whole branch in such a table, you'll just need to update the root's
parent
(a single row)You'll need to create a function:
and use it in a query:
I believe that with two extra columns to store the original Node right and left values (and all subsequent subnodes) the algorithm can be simplified. I have worked the examples with pencil and paper so if you find any holes in the algorithm please let me know.
The target Node (The new parent of Node that you are moving) is tNode. Left value of Target Node is tNode.L and right value is tNode.R. Similarly the node you are moving is mNode and left and right values for mNode are mNode.L and mNode.R. The two extra columns are mNode.SL and mNode.SR
So all in all we have 4 columns for manipulation R,L, SL and SR
Step1
calculate
Step2
Save the mNode original L and R into SL and SR columns
Step3
Now the mNode is detached from Tree and Tree is adjusted without mNode.
Step4
calculate
Step5
Now we have adjusted the Tree (and target node) to accept the number of nodes that were deleted.
Step6
Attach mNode at tNode and reset SL/SR column values
After all these steps we should have moved mNode under the tNode.
Moving subtrees around is very expensive and complex in the Nested Sets design.
You should consider a different design for representing trees.
For example, if you use the Path Enumeration design, you store the list of direct ancestors of each node as a concatenated string.
Then moving a subtree (say node 3 moves to be a child of node 2):
$row is an array that represents the row I have to move; it must be like this:
$row2 is an array that represents the destiny node;
...
Thanks for the idea of transforming the lft and rgt to their negative counterparts. I posted a more general approach for this here: Move node in Nested Sets tree.
The queryBatch() function encloses the query in a transaction.