sql >> Databasteknik >  >> RDS >> Sqlserver

Kaskadkopiera en rad med alla underordnade rader och deras underordnade rader osv

Jag antar att Blocks.BlockID , Elevations.ElevationID , Floors.FloorID , Panels.PanelID är primärnycklar och autogenererad IDENTITY .

  • Ett Block har många Elevations .
  • En Elevation har många Floors .
  • En Floor har många Panels .

Jag skulle använda MERGE med OUTPUT klausul.

MERGE kan INSERT , UPDATE och DELETE rows.I det här fallet behöver vi bara INSERT .

1=0 är alltid falsk, så koden NOT MATCHED BY TARGET del exekveras alltid. I allmänhet kan det finnas andra grenar, se dokument.WHEN MATCHED används vanligtvis för att UPDATE;WHEN NOT MATCHED BY SOURCE används vanligtvis för att DELETE , men vi behöver dem inte här.

Denna invecklade form av MERGE motsvarar enkel INSERT , men till skillnad från enkla INSERT dess OUTPUT klausulen gör det möjligt att referera till de kolumner som vi behöver. Den gör det möjligt att hämta kolumner från både käll- och destinationstabeller, vilket sparar en mappning mellan gamla befintliga ID:n och nya ID:n genererade av IDENTITY .

Blockera

Kopiera ett givet Block och kom ihåg ID av det nya Block .Vi kan använda enkla INSERT och SCOPE_IDENTITY här, eftersom BlockID är primärnyckel och endast en rad kan infogas.

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();

Höjder

Kopiera Elevations från gamla Block och tilldela dem till det nya Block .Kom ihåg mappningen mellan gamla IDs och nyligen genererade IDs i @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)
;

Golv

Kopiera Floors med hjälp av mappning mellan gammalt och nytt ElevationID .Kom ihåg mappningen mellan gamla IDs och nyligen genererade IDs i @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)
;

Paneler

Kopiera Panels med hjälp av mappning mellan gammalt och nytt FloorID .Detta är den sista detaljnivån, så vi kan använda enkla INSERT och kom inte ihåg mappningen av 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
;



  1. Hur skapar man en ny databas efter att ha installerat Oracle Database 11g Express Edition?

  2. Recordset stängt efter utförande av lagrad procedur

  3. SQL Server:Tabellvärdade funktioner kontra lagrade procedurer

  4. cakephp använder komponenter som kontrollermetoder