I have this Adjacency List Model table
Table:
CREATE TABLE node_structure_data ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, title VARCHAR(455) NOT NULL, parent_id INT(10) UNSIGNED DEFAULT NULL, PRIMARY KEY (id), FOREIGN KEY (parent_id) REFERENCES node_structure_data (id) ON DELETE CASCADE ON UPDATE CASCADE );
Output:
id title parent_id 1 Division NULL 2 Site 1 1 3 Paper 2 4 ms1 3 5 Site 2 1 6 Paper 5 7 ms2 6 8 Site 3 1 9 Paper 8 10 ms3 9
So I have the following query that duplicates a Site 1
e.g. and its children.
In this case, the children are Paper
with parent_id = 2
and ms1
with parent_id = 3
INSERT INTO node_structure_data (title,parent_id) WITH recursive max_id AS ( SELECT MAX(id) AS id FROM node_structure_data ), child_nodes AS ( SELECT n.id, title, parent_id, m.id+1 AS new_id, parent_id AS new_parent_id FROM node_structure_data n CROSS JOIN max_id AS m WHERE title='Site 1' UNION ALL SELECT n.id, n.parent_id, n.title, @row_num:=IF(@row_num=0,c.new_id,0) + 1 + @row_num AS new_id, c.new_id FROM child_nodes c INNER JOIN node_structure_data n ON n.parent_id = c.id CROSS JOIN ( SELECT @row_num:=0 AS rn ) AS vars ) SELECT title,new_parent_id FROM child_nodes ORDER BY new_id;
Output:
id title parent_id 1 Division NULL 2 Site 1 1 3 Paper 2 4 ms1 3 5 Site 2 1 6 Paper 5 7 ms2 6 8 Site 3 1 9 Paper 8 10 ms3 9 11 Site 1 1 12 Paper 11 13 ms1 12
As you can see Site 1
and its children got duplicated with a new unique id
.
However for the duplicated Site
title I want to have a prefix text Copy of
for the DUPLICATED Site 1
title
I only want that prefix for a Site/parent_id = 1
So that the duplicated nodes should look like this:
id title parent_id 1 Division NULL 2 Site 1 1 3 Paper 2 4 ms1 3 5 Site 2 1 6 Paper 5 7 ms2 6 8 Site 3 1 9 Paper 8 10 ms3 9 11 Copy of Site 1 1 12 Paper 11 13 ms1 12
I have tried to implement the IF and CONCAT in the query but for some reason, it doesn’t work, I don’t get any errors but the output stays the same.
IF(n.title LIKE '%Site%', CONCAT("Copy of ", n.title), n.title),
If the title contains the text Site
then I want to contact the prefix and the site title otherwise no concat.
Any ideas?
Any help is appreciated!!!
Advertisement
Answer
This solution shows how to insert a copy of a subtree and re-identify the descendants.
INSERT INTO node_structure_data (id, title, parent_id) WITH RECURSIVE subtree AS ( SELECT id, (SELECT MAX(id) FROM node_structure_data) AS last_id, CONCAT('Copy of ', title) AS title, parent_id FROM node_structure_data WHERE id = 2 -- i.e. title = 'Site 1' UNION ALL SELECT n.id, s.last_id, n.title, n.parent_id FROM subtree s JOIN node_structure_data n ON s.id = n.parent_id ), new_id AS ( SELECT id, last_id + ROW_NUMBER() OVER (ORDER BY id) AS new_id, title, parent_id FROM subtree ) SELECT n.new_id AS id, n.title, COALESCE(p.new_id, n.parent_id) AS parent_id FROM new_id n LEFT JOIN new_id p ON n.parent_id = p.id
Note that starting MySQL 8 setting user variables within expressions is deprecated and will be removed in a future release.
The following fiddle shows the results of each CTE – db<>fiddle