sql >> Databáze >  >> RDS >> Sqlserver

Kaskádově zkopírujte řádek se všemi podřízenými řádky a jejich podřízenými řádky atd

Předpokládám, že Blocks.BlockID , Elevations.ElevationID , Floors.FloorID , Panels.PanelID jsou primární klíče a automaticky generované IDENTITY .

  • Jeden Block má mnoho Elevations .
  • Jedna Elevation má mnoho Floors .
  • Jedno Floor má mnoho Panels .

Použil bych MERGE s OUTPUT klauzule.

MERGE může INSERT , UPDATE a DELETE řádky. V tomto případě potřebujeme pouze INSERT .

1=0 je vždy nepravda, takže NOT MATCHED BY TARGET část se vždy provede. Obecně mohou existovat další větve, viz dokumenty.WHEN MATCHED se obvykle používá k UPDATE;WHEN NOT MATCHED BY SOURCE se obvykle používá k DELETE , ale tady je nepotřebujeme.

Tato spletitá forma MERGE je ekvivalentní jednoduchému INSERT ,ale na rozdíl od jednoduchého INSERT jeho OUTPUT klauzule umožňuje odkazovat na sloupce, které potřebujeme. Umožňuje načíst sloupce ze zdrojových i cílových tabulek, čímž se ukládá mapování mezi starými existujícími ID a novými ID generovanými IDENTITY .

Blokovat

Zkopírujte jeden daný Block a zapamatujte si IDs nového Block .Můžeme použít jednoduchý INSERT a SCOPE_IDENTITY zde, protože BlockID je primární klíč a lze do něj vložit pouze jeden řádek.

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

Výšky

Zkopírujte Elevations ze starého Block a přiřadit je k novému Block .Pamatujte si na mapování mezi starými IDs a čerstvě vygenerovaná IDs v @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)
;

Podlaží

Zkopírujte Floors pomocí mapování mezi starým a novým ElevationID .Pamatujte si na mapování mezi starými IDs a čerstvě vygenerovaná IDs v @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)
;

Panely

Zkopírujte Panels pomocí mapování mezi starým a novým FloorID .Toto je poslední úroveň detailů, takže můžeme použít jednoduchý INSERT a nepamatujte si mapování 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. Uložte časový interval v PostgreSQL od Rails

  2. Jak navrhnout databázový model pro rezervační systém kina

  3. Cast String na int a použití v klauzuli Where

  4. Jak zavřít připojení sqlalchemy v MySQL