Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Copia a cascata una riga con tutte le righe figlio e le relative righe figlio, ecc

Presumo che Blocks.BlockID , Elevations.ElevationID , Floors.FloorID , Panels.PanelID sono chiavi primarie e IDENTITY generati automaticamente .

  • Un Block ha molte Elevations .
  • Un Elevation ha molti Floors .
  • Un Floor ha molti Panels .

Userei MERGE con OUTPUT clausola.

MERGE può INSERT , UPDATE e DELETE righe. In questo caso abbiamo solo bisogno di INSERT .

1=0 è sempre falso, quindi NOT MATCHED BY TARGET parte viene sempre eseguita. In generale, potrebbero esserci altri rami, vedere docs.WHEN MATCHED è solitamente usato per UPDATE;WHEN NOT MATCHED BY SOURCE di solito è usato per DELETE , ma non ne abbiamo bisogno qui.

Questa forma contorta di MERGE è equivalente al semplice INSERT ,ma a differenza del semplice INSERT il suo OUTPUT la clausola permette di fare riferimento alle colonne di cui abbiamo bisogno. Permette di recuperare colonne sia dalle tabelle di origine che da quelle di destinazione salvando così una mappatura tra i vecchi ID esistenti e i nuovi ID generati da IDENTITY .

Blocca

Copia un dato Block e ricorda il IDs del nuovo Block .Possiamo usare un semplice INSERT e SCOPE_IDENTITY qui, perché BlockID è la chiave primaria e può essere inserita solo una riga.

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

Prospettive

Copia Elevations dal vecchio Block e assegnali al nuovo Block .Ricorda la mappatura tra i vecchi IDs e IDs appena generati in @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)
;

Pavimenti

Copia Floors utilizzando la mappatura tra il vecchio e il nuovo ElevationID .Ricorda la mappatura tra i vecchi IDs e IDs appena generati in @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)
;

Riquadri

Copia Panels utilizzando la mappatura tra il vecchio e il nuovo FloorID .Questo è l'ultimo livello di dettagli, quindi possiamo usare un semplice INSERT e non ricordare la mappatura di 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
;