Presumo que
Blocks.BlockID
, Elevations.ElevationID
, Floors.FloorID
, Panels.PanelID
são chaves primárias e IDENTITY
geradas automaticamente . - Um
Block
tem muitasElevations
. - Uma
Elevation
tem muitosFloors
. - Um
Floor
tem muitosPanels
.
Eu usaria
MERGE
com OUTPUT
cláusula. MERGE
pode INSERT
, UPDATE
e DELETE
rows. Neste caso, precisamos apenas de INSERT
. 1=0
é sempre falso, então o NOT MATCHED BY TARGET
parte é sempre executada. Em geral, pode haver outras ramificações, veja docs.WHEN MATCHED
geralmente é usado para UPDATE
;WHEN NOT MATCHED BY SOURCE
é normalmente usado para DELETE
, mas não precisamos deles aqui. Esta forma complicada de
MERGE
é equivalente ao simples INSERT
,mas ao contrário do simples INSERT
sua OUTPUT
A cláusula permite fazer referência às colunas que precisamos. Permite recuperar colunas das tabelas de origem e destino, salvando assim um mapeamento entre os IDs existentes antigos e os novos IDs gerados por IDENTITY
. Bloquear
Copie um determinado
Block
e lembre-se do ID
do novo Block
.Podemos usar INSERT
simples e SCOPE_IDENTITY
aqui, porque BlockID
é chave primária e apenas uma linha pode ser inserida. DECLARE @blockToCopy int = 1;
DECLARE @VarNewBlockID int;
INSERT INTO Blocks
(ProjectID
,BlockName
,BlockDescription)
SELECT
ProjectID
,'NewNameTest'
,'NewDescTest'
FROM Blocks
WHERE Blocks.BlockID = @blockToCopy
;
SET @VarNewBlockID = SCOPE_IDENTITY();
Elevações
Copie
Elevations
do antigo Block
e atribua-os ao novo Block
.Lembre-se do mapeamento entre os IDs
antigos e IDs
recém-gerados em @MapElevations
. DECLARE @MapElevations TABLE(OldElevationID int, NewElevationID int);
MERGE INTO Elevations
USING
(
SELECT
ElevationID
,@VarNewBlockID AS BlockID
,ElevationName
,ElevationDescription
FROM Elevations
WHERE Elevations.BlockID = @blockToCopy
) AS Src
ON 1 = 0
WHEN NOT MATCHED BY TARGET THEN
INSERT
(BlockID
,ElevationName
,ElevationDescription)
VALUES
(Src.BlockID
,Src.ElevationName
,Src.ElevationDescription)
OUTPUT
Src.ElevationID AS OldElevationID
,inserted.ElevationID AS NewElevationID
INTO @MapElevations(OldElevationID, NewElevationID)
;
Andares
Copie
Floors
usando mapeamento entre o antigo e o novo ElevationID
.Lembre-se do mapeamento entre os IDs
antigos e IDs
recém-gerados em @MapFloors
. DECLARE @MapFloors TABLE(OldFloorID int, NewFloorID int);
MERGE INTO Floors
USING
(
SELECT
Floors.FloorID
,M.NewElevationID AS ElevationID
,Floors.FloorName
,Floors.FloorDescription
FROM
Floors
INNER JOIN Elevations ON Elevations.ElevationID = Floors.ElevationID
INNER JOIN @MapElevations AS M ON M.OldElevationID = Elevations.ElevationID
WHERE Elevations.BlockID = @blockToCopy
) AS Src
ON 1 = 0
WHEN NOT MATCHED BY TARGET THEN
INSERT
(ElevationID
,FloorName
,FloorDescription)
VALUES
(Src.ElevationID
,Src.FloorName
,Src.FloorDescription)
OUTPUT
Src.FloorID AS OldFloorID
,inserted.FloorID AS NewFloorID
INTO @MapFloors(OldFloorID, NewFloorID)
;
Painéis
Copie
Panels
usando mapeamento entre o antigo e o novo FloorID
.Este é o último nível de detalhes, então podemos usar INSERT
simples e não se lembre do mapeamento de IDs
. INSERT INTO Panels
(FloorID
,PanelName
,PanelDescription)
SELECT
M.NewFloorID
,Panels.PanelName
,Panels.PanelDescription
FROM
Panels
INNER JOIN Floors ON Floors.FloorID = Panels.FloorID
INNER JOIN Elevations ON Elevations.ElevationID = Floors.ElevationID
INNER JOIN @MapFloors AS M ON M.OldFloorID = Floors.FloorID
WHERE Elevations.BlockID = @blockToCopy
;