在mssql中复制多级相关表

Fer*_*min 2 t-sql sql-server sql-server-2008

我有4个相关的表,每个表与下一个表有1:N的关系,例如

One (OneID pk)
Two (TwoID pk, OneID fk)
Three (ThreeID pk, TwoID fk)
Four (FourID pk, ThreeID fk)
Run Code Online (Sandbox Code Playgroud)

当用户想要复制"One"中的记录以及表2,3和4中的所有相关记录时,我需要实现功能.

从前端开始,这样就可以使用户可以在现有记录上建立新记录.做这个的最好方式是什么?我有新插入的'OneID'和原始的'OneID'.

我想到这样做的一种方法是为每个表都有一个"复制"存储过程,每个表都有一个调用它的子表的游标为每行复制一次SP.

我想到的唯一另一种方法是让一个临时表记录每个表的原始+新ID,但这看起来很混乱,并且可能会失控.

有什么建议?

And*_*y M 5

如果你的PK IDENTITY列,你可以使用涉及技术MERGE,在说明这个问题.

以下是整个过程的编写方式:

DECLARE @OldID int, @NewID int;
SET @OldID = some_value;

DECLARE @TwoMapping TABLE (OldID int, NewID int);
DECLARE @ThreeMapping TABLE (OldID int, NewID int);

INSERT INTO One
SELECT columns
FROM One
WHERE OneID = @OldID;
SET @NewID = SCOPE_IDENTITY();
/*
That one was simple: one row is copied, so just reading SCOPE_IDENTITY()
after the INSERT. The actual mapping technique starts at this point.
*/

MERGE Two tgt
USING (
  SELECT
    @NewID AS OneID,
    other columns
  FROM Two t
  WHERE OneID = @OldID
) src
ON 0 = 1
WHEN NOT MATCHED THEN
  INSERT (columns) VALUES (src.columns)
OUTPUT src.TwoID, INSERTED.TwoID INTO @TwoMapping (OldID, NewID);
/*
As you can see, MERGE allows us to reference the source table in the
OUTPUT clause, in addition to the pseudo-tables INSERTED and DELETED,
and that is a great advantage over INSERT and the core of the method.
*/
Run Code Online (Sandbox Code Playgroud)

MERGE Three tgt
USING (
  SELECT
    map.NewID AS TwoID,
    t.other columns
  FROM Three t
    INNER JOIN @TwoMapping map ON t.TwoID = map.OldID
) src
ON 0 = 1
WHEN NOT MATCHED THEN
  INSERT (columns) VALUES (src.columns)
OUTPUT src.ThreeID, INSERTED.ThreeID INTO @ThreeMapping (OldID, NewID);
/*
Now that we've got a mapping table, we can easily substitute new FKs for the old
ones with a simple join. The same is repeated once again in the following MERGE.
*/

MERGE Four tgt
USING (
  SELECT
    map.NewID AS ThreeID,
    t.columns
  FROM Four t
    INNER JOIN @ThreeMapping map ON t.ThreeID = map.OldID
) src
ON 0 = 1
WHEN NOT MATCHED THEN
  INSERT (columns) VALUES (src.columns);
/*
The Four table is the last one in the chain of dependencies, so the last MERGE
has no OUTPUT clause. But if there were a Five table, we would go on like above.
*/
Run Code Online (Sandbox Code Playgroud)

或者你可能不得不使用游标,这似乎是在SQL Server 2005和早期版本中执行此操作的唯一(理智)方式.