复制父,子和孙记录

Joh*_*ger 10 sql sql-server sql-insert sql-server-2012

我有一个父表,表示一个文件,表中的每个记录在子表中有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])
);
Run Code Online (Sandbox Code Playgroud)

儿童

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]),
)
Run Code Online (Sandbox Code Playgroud)

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]),
)
Run Code Online (Sandbox Code Playgroud)

在我的存储过程中,我传入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
Run Code Online (Sandbox Code Playgroud)

问题归结为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.
Run Code Online (Sandbox Code Playgroud)

我以为我可以使用一些临时链接表来保存旧属性id和新属性id.我不知道如何将旧的属性ID与新的属性ID一起插入到临时表中.通过QuantlistId插入现有属性非常简单,但我无法弄清楚如何确保以某种方式将正确的新旧Id链接在一起,以便AttributeReference可以正确克隆表.如果我可以将QuantlistAttribute新旧Id链接起来,我可以加入该临时表并找出如何将新克隆引用的关系恢复到新克隆的属性.

对此的任何帮助都会很棒.我花了最后一天半试图弄清楚这一点没有运气:/

请原谅一些SQL的不一致.我快速重新写了sql,修剪了很多额外的列,相关表和这个问题不需要的约束.

编辑

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

ugh*_*hai 4

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

  1. QuantlistAttribute您可以根据顺序插入数据ORDER BY c.QuantlistAttributeId ASC

  2. 有一个临时表/表变量,其中 3 列

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

  4. 使用row_number()ordered by来匹配表变量的QuantlistAttributeId旧值和QuantlistAttributeId新值,并更新表变量中的值或旧的 QuantlistAttributeIdQuantlistAttributeIdsrow_number()id

  5. 使用临时表并join一次性AttributeReference插入记录。

注意: 在和ORDER BY期间需要匹配旧 记录,因为查看您的问题,似乎没有其他逻辑键将旧记录和新记录映射在一起。INSERT 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
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。