Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Kopieren Sie eine Zeile mit allen untergeordneten Zeilen und ihren untergeordneten Zeilen usw

Ich gehe davon aus, dass Blocks.BlockID , Elevations.ElevationID , Floors.FloorID , Panels.PanelID sind Primärschlüssel und automatisch generierte IDENTITY .

  • Ein Block hat viele Elevations .
  • Eine Elevation hat viele Floors .
  • Eine Floor hat viele Panels .

Ich würde MERGE verwenden mit OUTPUT Klausel.

MERGE kann INSERT , UPDATE und DELETE Zeilen. In diesem Fall brauchen wir nur INSERT .

1=0 ist immer falsch, also NOT MATCHED BY TARGET Teil wird immer ausgeführt. Im Allgemeinen könnte es andere Branches geben, siehe docs.WHEN MATCHED wird normalerweise zum UPDATE verwendet;WHEN NOT MATCHED BY SOURCE wird normalerweise zum DELETE verwendet , aber wir brauchen sie hier nicht.

Diese verschlungene Form von MERGE entspricht einfach INSERT , aber im Gegensatz zu einfachem INSERT sein OUTPUT -Klausel ermöglicht es, auf die Spalten zu verweisen, die wir benötigen. Sie ermöglicht das Abrufen von Spalten sowohl aus Quell- als auch aus Zieltabellen und spart so eine Zuordnung zwischen alten vorhandenen IDs und neuen IDs, die von IDENTITY generiert wurden .

Blockieren

Kopiere einen gegebenen Block und merken Sie sich die ID des neuen Block .Wir können einfach INSERT verwenden und SCOPE_IDENTITY hier, weil BlockID ist Primärschlüssel und es kann nur eine Zeile eingefügt werden.

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öhen

Kopieren Sie Elevations vom alten Block und weise sie dem neuen Block zu .Denken Sie an die Zuordnung zwischen alten IDs und frisch generierte IDs 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)
;

Böden

Kopieren Sie Floors mit Mapping zwischen alter und neuer ElevationID .Denken Sie an die Zuordnung zwischen alten IDs und frisch generierte IDs 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)
;

Panels

Kopieren Sie Panels mit Mapping zwischen alter und neuer FloorID .Dies ist die letzte Detailebene, also können wir einfach INSERT verwenden und denken Sie nicht an die Zuordnung von 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
;