【问题标题】:Adjacency list model duplicate parent & children邻接表模型重复父子节点
【发布时间】:2021-10-15 12:33:30
【问题描述】:

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

我有这张表名为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

如何复制节点及其子节点?
例如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

【问题讨论】:

  • 哪个版本的 MySQL?您能否在您的问题中添加针对Site 1 示例的算法执行后表格的内容如何?
  • 哪个版本的 MySQL?
  • 版本 8.0 @trincot
  • 什么是 ms1 ?它甚至不是内部输出。并且您希望它在所需的输出中?
  • 您可能需要为此编写一个存储过程。

标签: mysql hierarchical-data adjacency-list


【解决方案1】:

以下方法首先估计新的最大值,然后使用递归 cte 查找所需节点“站点 1”的所有子节点,并在没有其他并发写入表的情况下确定它们可能的新 parent_id

我建议在操作期间在transactionlocking 表中运行以下命令,以防止并发表修改。

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

请参阅下面的工作 db 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

让我知道这是否适合你。

【讨论】:

  • 很好的答案!成功了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多