Предполагам, че Blocks.BlockID
, Elevations.ElevationID
, Floors.FloorID
, Panels.PanelID
са първични ключове и автоматично генерирани IDENTITY
.
- Един
Block
има многоElevations
. - Една
Elevation
има многоFloors
. - Един
Floor
има многоPanels
.
Бих използвал MERGE
с OUTPUT
клауза.
MERGE
може INSERT
, UPDATE
и DELETE
редове. В този случай имаме нужда само от INSERT
.
1=0
винаги е невярно, така че NOT MATCHED BY TARGET
част винаги се изпълнява. По принцип може да има други разклонения, вижте документите.WHEN MATCHED
обикновено се използва за UPDATE
;WHEN NOT MATCHED BY SOURCE
обикновено се използва за DELETE
, но не ни трябват тук.
Тази сложна форма на MERGE
е еквивалентен на обикновен INSERT
, но за разлика от простия INSERT
неговият OUTPUT
клауза позволява препращане към колоните, от които се нуждаем. Позволява извличане на колони както от изходни, така и от таблици на местоназначение, като по този начин спестява съпоставяне между стари съществуващи идентификатори и нови идентификатори, генерирани от IDENTITY
.
Блокиране
Копирайте даден Block
и запомнете IDs
на новия Block
.Можем да използваме просто INSERT
и SCOPE_IDENTITY
тук, защото BlockID
е първичен ключ и може да бъде вмъкнат само един ред.
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();
Коти
Копирайте Elevations
от стария Block
и ги присвоете на новия Block
.Запомнете съпоставянето между старите IDs
и прясно генерирани IDs
в @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)
;
Етажи
Копирайте Floors
използвайки картографиране между стар и нов ElevationID
.Запомнете съпоставянето между старите IDs
и прясно генерирани IDs
в @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)
;
Панели
Копирайте Panels
използвайки съпоставяне между стар и нов FloorID
.Това е последното ниво на подробности, така че можем да използваме просто INSERT
и не запомнете съпоставянето на 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
;