【问题标题】:Duplicating parent, child and grandchild records复制父、子和孙记录
【发布时间】:2015-05-08 05:19:58
【问题描述】:

我有一个表示文档的父表,表中的每条记录在子表中都有 n 个子记录。每个子记录可以有 n 个孙记录。这些记录处于已发布状态。当用户想要修改已发布的文档时,我们需要克隆父文档及其所有子孙。

表结构如下:

家长

CREATE TABLE [ql].[Quantlist] (
    [QuantlistId]   INT           IDENTITY (1, 1) NOT NULL,
    [StateId]       INT           NOT NULL,
    [Title]         VARCHAR (500) NOT NULL,
    CONSTRAINT [PK_Quantlist] PRIMARY KEY CLUSTERED ([QuantlistId] ASC),
    CONSTRAINT [FK_Quantlist_State] FOREIGN KEY ([StateId]) REFERENCES [ql].[State] ([StateId])
);

孩子

CREATE TABLE [ql].[QuantlistAttribute]
(
    [QuantlistAttributeId] INT IDENTITY (1, 1),
    [QuantlistId] INT NOT NULL,
    [Narrative] VARCHAR (500) NOT NULL,
    CONSTRAINT [PK_QuantlistAttribute] PRIMARY KEY ([QuantlistAttributeId]), 
    CONSTRAINT [FK_QuantlistAttribute_QuantlistId] FOREIGN KEY ([QuantlistId]) REFERENCES [ql].[Quantlist]([QuantlistId]),
)

孙子

CREATE TABLE [ql].[AttributeReference]
(
    [AttributeReferenceId] INT IDENTITY (1, 1),
    [QuantlistAttributeId] INT NOT NULL,
    [Reference] VARCHAR (250) NOT NULL,
    CONSTRAINT [PK_QuantlistReference] PRIMARY KEY ([AttributeReferenceId]), 
    CONSTRAINT [FK_QuantlistReference_QuantlistAttribute] FOREIGN KEY ([QuantlistAttributeId]) REFERENCES [ql].[QuantlistAttribute]([QuantlistAttributeId]),
)

在我的存储过程中,我传入QuantlistId 我想克隆为@QuantlistId。由于QuantlistAttribute 表有一个ForeignKey,我也可以轻松地克隆它。

INSERT INTO [ql].[Quantlist] (
    [StateId],
    [Title],
) SELECT 
    1,
    Title,
    FROM [ql].[Quantlist]
    WHERE QuantlistId = @QuantlistId

SET @ClonedId = SCOPE_IDENTITY()

INSERT INTO ql.QuantlistAttribute(
        QuantlistId
        ,Narrative)
    SELECT 
        @ClonedId,
        Narrative,
    FROM ql.QuantlistAttribute
    WHERE QuantlistId = @QuantlistId

问题归结为AttributeReference。如果我克隆了 30 条 QuantlistAttribute 记录,如何克隆引用表中的记录并将它们与我刚刚插入到 QuantlistAttribute 表中的新记录匹配?

    INSERT INTO ql.AttributeReference(
            QuantlistAttributeId,
            Reference,)
        SELECT 
            QuantlistAttributeId,
            Reference,
        FROM ql.QuantlistReference
        WHERE ??? I don't have a key to go off of for this.

我想我可以使用一些临时链接表来做到这一点,这些链接表包含旧属性 id 和新属性 id。我不知道如何将旧的属性 ID 与新的属性 ID 一起插入到临时表中。通过 QuantlistId 插入现有属性很容易,但我不知道如何确保以某种方式将正确的新旧 Id 链接在一起,以便可以正确克隆 AttributeReference 表。如果我可以将 QuantlistAttribute 新旧 ID 链接起来,我可以加入该临时表并弄清楚如何将新克隆的引用恢复到新克隆的属性的关系。

对此的任何帮助都会很棒。我花了最后一天半的时间试图解决这个问题,但没有运气:/

请原谅一些 SQL 不一致的地方。我很快就重新编写了 sql,删除了许多此问题不需要的额外列、相关表和约束。

编辑

经过一番挖掘后,我发现 OUTPUT 可能对此有用。有没有办法使用 OUTPUT 将我刚刚插入的 QuantlistAttributeId 记录映射到它们源自的 QuantlistAttributeId

【问题讨论】:

  • 你在表QuantlistAttribute中有逻辑键吗?

标签: sql sql-server sql-server-2012 sql-insert


【解决方案1】:

您可以使用OUTPUT 来获取插入的行。

  1. 可以按照ORDER BY c.QuantlistAttributeId ASC的顺序将数据插入QuantlistAttribute

  2. 有一个 3 列的临时表/表变量

    • 一个 id 标识列
    • 新的 QuantlistAttributeId
    • 旧的 QuantlistAttributeId。
  3. 使用 OUTPUT 将 QuantlistAttribute 的新标识值插入到临时表/表变量中。 新 ID 的生成顺序与 c.QuantlistAttributeId

  4. 相同
  5. 使用由QuantlistAttributeId 排序的row_number() 来匹配基于表变量的row_number()id 的旧QuantlistAttributeId 和新QuantlistAttributeIds,并更新表变量中的值或旧的QuantlistAttributeId表变量

  6. 将临时表和joinAttributeReference一起使用,一次性插入记录。

注意: ORDER BYINSERT INTO SELECTROW_NUMBER() 期间需要匹配旧的QuantlistAttributeId,因为查看您的问题,似乎没有其他逻辑键可以将新旧记录映射在一起。

查询上述步骤

DECLARE @ClonedId INT,@QuantlistId INT = 0

INSERT INTO [ql].[Quantlist] (
    [StateId],
    [Title]
) SELECT 
    1,
    Title
    FROM [ql].[Quantlist]
    WHERE QuantlistId = @QuantlistId

SET @ClonedId = SCOPE_IDENTITY()
--Define a table variable to store the new QuantlistAttributeID and use it to map with the Old QuantlistAttributeID
DECLARE @temp TABLE(id int identity(1,1), newAttrID INT,oldAttrID INT)

INSERT INTO ql.QuantlistAttribute(
        QuantlistId
        ,Narrative)
        --New QuantlistAttributeId are created in the same order as old QuantlistAttributeId  because of ORDER BY
        OUTPUT inserted.QuantlistAttributeId,NULL INTO @temp
    SELECT 
        @ClonedId,
        Narrative
    FROM ql.QuantlistAttribute c
    WHERE QuantlistId = @QuantlistId
    --This is required to keep new ids generated in the same order as old
    ORDER BY c.QuantlistAttributeId ASC

    ;WITH CTE AS
    (
        SELECT c.QuantlistAttributeId,
        --Use ROW_NUMBER to get matching id which is same as the one generated in @temp
        ROW_NUMBER()OVER(ORDER BY c.QuantlistAttributeId ASC) id
        FROM ql.QuantlistAttribute c
        WHERE QuantlistId = @QuantlistId
    )
    --Update the old value in @temp 
    UPDATE T
    SET oldAttrID = CTE.QuantlistAttributeId
    FROM @temp T
    INNER JOIN CTE ON T.id = CTE.id


INSERT INTO ql.AttributeReference(
            QuantlistAttributeId,
            Reference)
        SELECT 
            T.NewAttrID,
            Reference
        FROM ql.AttributeReference R
        --Use OldAttrID to join with ql.AttributeReference and insert NewAttrID
        INNER JOIN @temp T
        ON T.oldAttrID = R.QuantlistAttributeId

希望这会有所帮助。

【讨论】:

  • 这非常有效!非常感谢您的帮助。我曾尝试查看表格表达式,但很难理解它们。我是 C# 开发人员,但不会写太多 SQL
猜你喜欢
  • 2011-08-07
  • 2021-05-25
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-13
  • 2019-02-21
  • 1970-01-01
相关资源
最近更新 更多