复制父,子和孙记录

时间:2015-05-08 05:19:59

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

我有一个父表,表示一个文件,表中的每条记录都有一个子表中的 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

1 个答案:

答案 0 :(得分:3)

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

  1. 您可以根据QuantlistAttribute

  2. 的顺序将数据插入ORDER BY c.QuantlistAttributeId ASC
  3. 有一个3列

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

  5. 相同
  6. 使用row_number()订购的QuantlistAttributeId来匹配旧QuantlistAttributeId和新QuantlistAttributeIds基于row_number()id的{​​{1}}表变量并更新表变量

  7. 中的值或旧的QuantlistAttributeId
  8. 使用临时表和join AttributeReference并一次性插入记录。

  9. 注意: 的 在ORDER BYINSERT INTO SELECT期间需要ROW_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
    

    希望这有帮助。