Предполагам, че 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
;