sql >> Base de Datos >  >> RDS >> Sqlserver

Copie en cascada una fila con todas las filas secundarias y sus filas secundarias, etc.

Supongo que Blocks.BlockID , Elevations.ElevationID , Floors.FloorID , Panels.PanelID son claves primarias y IDENTITY generadas automáticamente .

  • Un Block tiene muchas Elevations .
  • Una Elevation tiene muchos Floors .
  • Un Floor tiene muchos Panels .

Usaría MERGE con OUTPUT cláusula.

MERGE puede INSERT , UPDATE y DELETE filas. En este caso solo necesitamos INSERT .

1=0 siempre es falso, por lo que NOT MATCHED BY TARGET la parte siempre se ejecuta. En general, podría haber otras ramas, consulte los documentos. WHEN MATCHED generalmente se usa para UPDATE;WHEN NOT MATCHED BY SOURCE generalmente se usa para DELETE , pero no los necesitamos aquí.

Esta forma complicada de MERGE es equivalente al simple INSERT ,pero a diferencia del simple INSERT su OUTPUT permite hacer referencia a las columnas que necesitamos. Permite recuperar columnas de las tablas de origen y de destino, guardando así un mapeo entre los ID antiguos existentes y los ID nuevos generados por IDENTITY .

Bloquear

Copie un Block dado y recuerda el IDs del nuevo Block .Podemos usar INSERT simple y SCOPE_IDENTITY aquí, porque BlockID es clave principal y solo se puede insertar una fila.

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

Elevaciones

Copiar Elevations del antiguo Block y asígnelos al nuevo Block .Recuerde el mapeo entre IDs antiguos y IDs recién generados en @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)
;

Pisos

Copiar Floors usando el mapeo entre el antiguo y el nuevo ElevationID .Recuerde el mapeo entre IDs antiguos y IDs recién generados en @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)
;

Paneles

Copiar Panels usando el mapeo entre el antiguo y el nuevo FloorID .Este es el último nivel de detalles, por lo que podemos usar INSERT simple y no recuerdes el mapeo de 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
;