Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Copie en cascade une ligne avec toutes les lignes enfants et leurs lignes enfants, etc.

Je suppose que Blocks.BlockID , Elevations.ElevationID , Floors.FloorID , Panels.PanelID sont des clés primaires et IDENTITY généré automatiquement .

  • Un Block a de nombreuses Elevations .
  • Une Elevation a plusieurs Floors .
  • Un Floor a de nombreux Panels .

J'utiliserais MERGE avec OUTPUT clause.

MERGE peut INSERT , UPDATE et DELETE rows. Dans ce cas, nous n'avons besoin que de INSERT .

1=0 est toujours faux, donc le NOT MATCHED BY TARGET part est toujours exécutée.En général, il pourrait y avoir d'autres branches, voir docs.WHEN MATCHED est généralement utilisé pour UPDATE;WHEN NOT MATCHED BY SOURCE est généralement utilisé pour DELETE , mais nous n'en avons pas besoin ici.

Cette forme alambiquée de MERGE équivaut à un simple INSERT , mais contrairement au simple INSERT sa OUTPUT La clause permet de faire référence aux colonnes dont nous avons besoin. Elle permet de récupérer les colonnes des tables source et destination, économisant ainsi un mappage entre les anciens identifiants existants et les nouveaux identifiants générés par IDENTITY .

Bloquer

Copiez un Block donné et mémorisez l'IDs du nouveau Block .Nous pouvons utiliser de simples INSERT et SCOPE_IDENTITY ici, car BlockID est la clé primaire et une seule ligne peut être insérée.

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

Altitudes

Copier Elevations de l'ancien Block et affectez-les au nouveau Block .Mémoriser le mappage entre les anciens IDs et des IDs fraîchement générés dans @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)
;

Étages

Copier Floors en utilisant le mappage entre l'ancien et le nouveau ElevationID .Mémoriser le mappage entre les anciens IDs et des IDs fraîchement générés dans @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)
;

Panneaux

Copier Panels en utilisant le mappage entre l'ancien et le nouveau FloorID .Ceci est le dernier niveau de détails, nous pouvons donc utiliser de simples INSERT et ne vous souvenez pas du mappage des 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
;