级联复制包含所有子行及其子行等的行

时间:2017-01-11 16:21:58

标签: sql sql-server sql-server-2008

我正在尝试跟踪商业建筑结构中的物品(特别是混凝土覆层)。

  • 项目可以有多个区块(一个区块是一个单独的建筑物)
  • 一个街区可以有多个高程(建筑面;北,东等)
  • 海拔可以有很多楼层(高层建筑)
  • 地板可以有许多面板(面板是混凝土包层的一部分)

为了在数据库中构建面板以便跟踪它们时更容易,我希望能够复制一个块(因为10次中有9次,每个块都有相同的细微变化)

就表而言 -

Blocks.BlockID, 
Blocks.BlockName, 
Blocks.BlockDescription, 
Projects.ProjectID

立面

Elevations.ElevationID, 
Elevations.ElevationName, 
Elevations.ElevationDescription, 
Blocks.BlockID

地面

Floors.FloorID, 
Floors.FloorName, 
Floors.FloorDescription, 
Elevations.ElevationID

面板

Panels.PanelID, 
Panels.PanelName, 
Panels.PanelDescription, 
Floors.FloorID

如果我复制一个块,则需要

  1. 复制当前块,但用户应该能够选择Blocks.name。
  2. 复制该块上的所有高程
  3. 复制每个高程的所有楼层
  4. 复制每个楼层的所有面板
  5. 如果您需要了解其他任何内容,请告诉我,感谢您提前提供帮助!

    我的尝试(在之前的建议之后)

    DECLARE @blockToCopy int = 1
    DECLARE @BlockOutput table
    ( BlockID int);
    DECLARE @ElevationsOutput table
    (  ElevationID int, BlockID int );
    DECLARE @FloorsOutput table
    (  FloorID int, ElevationID int );
    DECLARE @ItemsOutput table
    (  ItemID int, FloorID int );
    
    INSERT INTO Blocks
    (ProjectID,BlockName,BlockDescription) 
        OUTPUT 
        INSERTED.BlockID
        INTO @BlockOutput
    SELECT ProjectID,'NewNameTest','NewDescTest' 
    from Blocks
    WHERE BlockID=@blockToCopy
    
    INSERT INTO Elevations
    (BlockID,ElevationName,ElevationDescription) 
        OUTPUT 
        INSERTED.ElevationID,
        INSERTED.BlockID
        INTO @ElevationsOutput
    SELECT (SELECT BlockID from @BlockOutput),ElevationName,ElevationDescription 
    from Elevations
    WHERE BlockID=@blockToCopy
    
    INSERT INTO Floors
    (ElevationID,FloorName,FloorDescription)
        OUTPUT 
        INSERTED.FloorID,
        INSERTED.ElevationID
        INTO @FloorsOutput
    SELECT (SELECT top 1 ElevationID from @ElevationsOutput order by ElevationID desc), FloorName,FloorDescription 
    from Floors
    WHERE ElevationID in (SELECT ElevationID from @ElevationsOutput)
    

    在第二个级联(尝试复制每个高程内的所有楼层)之后出错。我知道为什么它会出错(而不是将原始ID和新ID一起列出来复制到,我自己输出新的ID因此它没有任何要复制的东西,因为它们还不存在)但我不知道如何解决它。

1 个答案:

答案 0 :(得分:1)

我认为Blocks.BlockIDElevations.ElevationIDFloors.FloorIDPanels.PanelID是主键并自动生成IDENTITY

  • 一个Block有很多Elevations
  • 一个Elevation有很多Floors
  • 一个Floor有很多Panels

我将MERGEOUTPUT条款一起使用。

MERGE可以INSERTUPDATEDELETE行。 在这种情况下,我们只需要INSERT

1=0始终为false,因此始终会执行NOT MATCHED BY TARGET部分。 一般来说,可能还有其他分支,请参阅docs。 WHEN MATCHED通常用于UPDATE; WHEN NOT MATCHED BY SOURCE通常用于DELETE,但我们在这里不需要它们。

这种令人费解的MERGE形式相当于简单INSERT, 但与简单INSERT不同,它的OUTPUT子句允许引用我们需要的列。 它允许从源表和目标表中检索列,从而节省映射 旧现有ID与IDENTITY生成的新ID之间。

阻止

复制一个Block,并记住新ID的{​​{1}}。 我们可以在这里使用简单的BlockINSERT, 因为SCOPE_IDENTITY是主键,只能插入一行。

BlockID

<强>立面

从旧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(); 复制Elevations并将其分配给新的Block。 请记住旧BlockIDs中新生成的IDs之间的映射。

@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) ; 之间的映射复制Floors。 请记住旧ElevationIDIDs中新生成的IDs之间的映射。

@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。 这是最后一级的细节,因此我们可以使用简单的FloorID而不是 记住INSERT

的映射
IDs