邻接表模型重复 parent & children

Adjacency list model duplicate parent & children

MySQL 中的分层数据使用邻接表模型

我把这个 table 命名为 node_structur_data

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
);

输出:

id  title   parent_id
1   Division  NULL
2   Site 1    1
3   Paper     2
4   ms1       3

如何复制节点及其 children?
例如Site 1
ID & parent_id 应该是唯一的,但标题应该保持不变。

预期输出:

id  title   parent_id
1   Division  NULL
2   Site 1    1
3   Paper     2
4   ms1       3
5   Site 1    1
6   Paper     5
7   ms1       6

以下方法首先估计新的最大值,然后使用递归 cte 查找所需节点的所有子节点 'Site 1' 并确定它们的新可能 parent_id 如果没有其他并发写入table.

我会推荐运行以下在transaction and lockingtable操作过程中防止并发table修改。

为了测试这种方法,我添加了一些额外的示例数据,这些数据包含在下面,但是您可能会在带有初始示例数据的演示中看到该方法 here

请参阅下面工作数据库 fiddle 的输出:

架构(MySQL v8.0)

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
);

INSERT INTO node_structure_data
  (`id`, `title`, `parent_id`)
VALUES
  ('1', 'Division', NULL),
  ('2', 'Site 1', '1'),
  ('3', 'Paper', '2'),
  ('4', 'ms1', '3'),
  ('5', 'ms2', '3'),
  ('6', 'os1', '4'),
  ('7', 'os2', '4'),
  ('8', 'gs1', '1'),
  ('9', 'hs1', '3'),
  ('10','js1','9');

查询#1

select 'Before Insert';
Before Insert
Before Insert

查询 #2

select * from node_structure_data;
id title parent_id
1 Division
2 Site 1 1
3 Paper 2
4 ms1 3
5 ms2 3
6 os1 4
7 os2 4
8 gs1 1
9 hs1 3
10 js1 9

查询#3

select 'Possible Data Changes';
Possible Data Changes
Possible Data Changes

查询#4

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.title,
        n.parent_id,
        @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 * FROM child_nodes;
id title parent_id new_id new_parent_id
2 Site 1 1 11 1
3 Paper 2 12 11
4 ms1 3 13 12
5 ms2 3 14 12
9 hs1 3 15 12
6 os1 4 16 13
7 os2 4 17 13
10 js1 9 18 15

查询 #5 - 执行实际插入

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.title,
        n.parent_id,
        @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;

没有要显示的结果。


查询 #6

select 'AFTER INSERT';
AFTER INSERT
AFTER INSERT

查询 #7

select * from node_structure_data;
id title parent_id
1 Division
2 Site 1 1
3 Paper 2
4 ms1 3
5 ms2 3
6 os1 4
7 os2 4
8 gs1 1
9 hs1 3
10 js1 9
11 Site 1 1
12 Paper 11
13 ms1 12
14 ms2 12
15 hs1 12
16 os1 13
17 os2 13
18 js1 15

View on DB Fiddle

让我知道这是否适合你。