当前位置: 首页 > 面试题库 >

如何深度复制一组数据,并更改FK引用以指向所有副本?

厉文栋
2023-03-14
问题内容

假设我有表A和表B。表B引用了表A。我想深入复制表A和表B中的一组行。我希望所有新的表B行都引用新的表A行。

请注意,我没有将行复制到任何其他表中。表A中的行将被复制到表A中,表B中的行将被复制到表B中。

如何确保将外键引用作为副本的一部分进行重新调整?

为了澄清,我试图找到一种通用的方式来做到这一点。我给出的示例涉及两个表,但是在实践中,依赖关系图可能要复杂得多。甚至是一种动态生成SQL的通用方法也可以。

更新:

人们在问为什么这是必要的,所以我给一些背景知识。可能太多了,但这里有:

我正在使用一个旧的桌面应用程序,该应用程序已移至客户端-
服务器模型。但是,该应用程序仍使用基本的内部二进制文件格式来存储其表的数据。数据文件只是一个标题,后跟一系列行,每行都是二进制序列化的字段值,其顺序由模式文本文件确定。唯一的好处是它非常快。在其他各个方面都很糟糕。我正在将应用程序移至SQL
Server,并尝试不降低性能。

这是一种调度应用程序;数据对任何人都不重要,也没有必要进行审核跟踪等。它不是大量的数据,如果数据库太大,我们不必保留非常旧的数据。

他们习惯于使用的一项功能是能够复制整个计划,以创建他们可以采用的“假设分析”方案。任何用户都可以根据需要多次执行此操作。在旧数据库中,每个日程表的数据文件都存储在它们自己的数据文件夹中,该文件夹由名称标识。因此,复制日程表就像复制数据文件夹并重命名一样简单。

必须 能够使用SQL
Server有效地执行相同的操作,否则迁移将无法进行。也许您在想,为了避免冗余,我只能复制实际上已更改的数据。但这听起来实在太复杂了以至于不可行。

要将其他扳手投入使用,可以有一个计划数据文件夹层次结构。因此,数据文件夹可能包含一个数据文件夹,该数据文件夹可能包含一个数据文件夹。并且复制可以发生在任何级别。

在SQL Server中,我实现了一个嵌套集层次结构来模仿这一点。我有一个像这样的DATA_SET表:

CREATE TABLE dbo.DATA_SET
(
    DATA_SET_ID UNIQUEIDENTIFIER PRIMARY KEY,
    NAME NVARCHAR(128) NOT NULL,
    LFT INT NOT NULL,
    RGT INT NOT NULL
)

因此,有一个数据集的树形结构。每个数据集代表一个时间表,并且可以包含子数据集。每个表中的每一行都有一个DATA_SET_ID
FK引用,指示它属于哪个数据集。每当我复制数据集时,我都会将表中该数据集的所有行以及所有其他数据集复制到同一张表中,但要引用新的数据集。

因此,这是一个简单的具体示例:

CREATE TABLE FOO
(
    FOO_ID BIGINT PRIMARY KEY,
    DATA_SET_ID BIGINT FOREIGN KEY REFERENCES DATA_SET(DATA_SET_ID) NOT NULL
)


CREATE TABLE BAR
(
    BAR_ID BIGINT PRIMARY KEY,
    DATA_SET_ID BIGINT FOREIGN KEY REFERENCES DATA_SET(DATA_SET_ID) NOT NULL,
    FOO_ID UNIQUEIDENTIFIER PRIMARY KEY
)

INSERT INTO FOO
SELECT 1, 1 UNION ALL
SELECT 2, 1 UNION ALL
SELECT 3, 1 UNION ALL

INSERT INTO BAR
SELECT 1, 1, 1
SELECT 2, 1, 2
SELECT 3, 1, 3

因此,假设我将数据集1复制到ID 2的新数据集中。复制后,表将如下所示:

FOO
FOO_ID, DATA_SET_ID
1    1
2    1
3    1
4    2
5    2
6    2

BAR
BAR_ID, DATA_SET_ID, FOO_ID
1    1    1
2    1    2
3    1    3
4    2    4
5    2    5
6    2    6

如您所见,新的BAR行引用了新的FOO行。我要问的不是DATA_SET_ID的重新布线。我想问的是一般重新布线外键。

所以,那肯定是太多的信息,但是您去了。

我敢肯定,像这样批量复制数据的想法会引起很多关于性能的担忧。桌子不会很​​大。我不希望任何表中有超过1000条记录,并且大多数表都比这小得多。可以直接删除旧数据集,而不会造成任何影响。

谢谢,泰德兹


问题答案:

这是一个包含三个表的示例,可能会帮助您入门。

数据库架构

CREATE TABLE users
    (user_id int auto_increment PRIMARY KEY, 
     user_name varchar(32));
CREATE TABLE agenda
    (agenda_id int auto_increment PRIMARY KEY, 
     `user_id` int, `agenda_name` varchar(7));
CREATE TABLE events
    (event_id int auto_increment PRIMARY KEY, 
     `agenda_id` int, 
     `event_name` varchar(8));

一个SP来克隆用户的日程和事件记录

DELIMITER $$
CREATE PROCEDURE clone_user(IN uid INT)
BEGIN
    DECLARE last_user_id INT DEFAULT 0;

    INSERT INTO users (user_name)
    SELECT user_name
      FROM users
     WHERE user_id = uid;

    SET last_user_id = LAST_INSERT_ID();

    INSERT INTO agenda (user_id, agenda_name)
    SELECT last_user_id, agenda_name
      FROM agenda
     WHERE user_id = uid;

    INSERT INTO events (agenda_id, event_name)
    SELECT a3.agenda_id_new, e.event_name
      FROM events e JOIN
    (SELECT a1.agenda_id agenda_id_old, 
           a2.agenda_id agenda_id_new
      FROM
    (SELECT agenda_id, @n := @n + 1 n 
       FROM agenda, (SELECT @n := 0) n 
      WHERE user_id = uid 
      ORDER BY agenda_id) a1 JOIN
    (SELECT agenda_id, @m := @m + 1 m 
       FROM agenda, (SELECT @m := 0) m 
      WHERE user_id = last_user_id 
      ORDER BY agenda_id) a2 ON a1.n = a2.m) a3 
         ON e.agenda_id = a3.agenda_id_old;
END$$
DELIMITER ;

克隆用户

CALL clone_user(3);

这是 SQLFiddle 演示。



 类似资料:
  • 问题内容: 如何将Item结构和所有指针复制到新结构? 我不希望新结构引用旧结构。 问题答案: 本质上您想要的是标准库不支持的深层副本。 您的选择: “手动”执行复制,例如,创建新的结构并复制字段,其中必须以递归方式手动复制指针或切片/地图/通道/等。 通过将您的结构分配给另一个可复制所有字段的结构,这是最容易做到的,因此,您基本上只需要培养指针/地图/切片等(但需要递归)。 使用外部库,例如,或

  • 问题内容: 鉴于以下Dockerfile 在复制的测试目录中,我已将文件许可权设置为770。 如果在容器内进行操作,则无法访问测试目录中的任何文件或子目录。似乎此问题与aufs文件系统中的所有权有关,在该文件系统中,复制的目录仍然由root拥有,并且权限设置为770。 是否有解决此问题的方法以正确设置权限?一种可能是在复制之前将原始目录的权限设置为容器用户的uid。但这似乎更像是一种hack。 问

  • 使用测试字符串: 是否可以将所有StringX作为反向引用?目前,我尝试的内容每次都会被覆盖,因此我最终会得到一个匹配项,即最后一个匹配项。 例如使用这样的正则表达式: 最后总是以的匹配结束。 到目前为止,我发现的最好的方法是删除上面的并在空格上爆炸,但我对是否有一种方法可以纯粹使用正则表达式来做到这一点很感兴趣。 专门更新PHP,实现这一点的最佳方法是什么?

  • 本文向大家介绍JavaScript 数组的深度复制解析,包括了JavaScript 数组的深度复制解析的使用技巧和注意事项,需要的朋友参考一下 对于javascript而言,数组是引用类型,如果要想复制一个数组就要动脑袋想想了,因为包括concat、slice在内的函数,都是浅层复制。也就是说,对于一个二维数组来说,用concat来做复制,第二维的数组还是引用,修改了新数组同样会使旧数组发生改变。

  • 问题内容: 我有一个叫Meal的课程 而且我有很多餐: 我想复制该数组,然后在其中一个实例中对Meal实例进行一些更改,而在第二个实例中不更改Meal实例,我将如何对其进行深拷贝? 问题答案: 由于是一个快速数组,所以该语句 将有效地复制原始数组。 但是,由于Meal是一 类 ,因此新数组将包含对原始膳食中相同膳食的引用。 如果您也想复制进餐内容,那么在一个数组中更改进餐不会在另一个数组中更改进餐

  • 问题内容: 我想使用自己的Node类在Java中实现树结构。但是我很困惑如何进行深层复制来复制树。 我的Node类将是这样的: 我是递归的新手,所以有什么我可以学习的代码吗?谢谢! 问题答案: 尝试