Using merge..output to get mapping between source.id and target.id

后端 未结 2 650
隐瞒了意图╮
隐瞒了意图╮ 2020-11-22 00:13

Very simplified, I have two tables Source and Target.

declare @Source table (SourceID int identity(1,2), SourceName varchar(50))
declare @Target table (Targe         


        
相关标签:
2条回答
  • 2020-11-22 00:50

    In my opinion this is a great use of MERGE and output. I've used in several scenarios and haven't experienced any oddities to date. For example, here is test setup that clones a Folder and all Files (identity) within it into a newly created Folder (guid).

    DECLARE @FolderIndex TABLE (FolderId UNIQUEIDENTIFIER PRIMARY KEY, FolderName varchar(25));
    INSERT INTO @FolderIndex 
        (FolderId, FolderName)
        VALUES(newid(), 'OriginalFolder');
    
    DECLARE @FileIndex TABLE (FileId int identity(1,1) PRIMARY KEY, FileName varchar(10));
    INSERT INTO @FileIndex 
        (FileName)
        VALUES('test.txt');
    
    DECLARE @FileFolder TABLE (FolderId UNIQUEIDENTIFIER, FileId int, PRIMARY KEY(FolderId, FileId));
    INSERT INTO @FileFolder 
        (FolderId, FileId)
        SELECT  FolderId, 
                FileId
        FROM    @FolderIndex
        CROSS JOIN  @FileIndex;  -- just to illustrate
    
    DECLARE @sFolder TABLE (FromFolderId UNIQUEIDENTIFIER, ToFolderId UNIQUEIDENTIFIER);
    DECLARE @sFile TABLE (FromFileId int, ToFileId int);
    
    -- copy Folder Structure
    MERGE @FolderIndex fi
    USING   (   SELECT  1 [Dummy],
                        FolderId, 
                        FolderName
                FROM    @FolderIndex [fi]
                WHERE   FolderName = 'OriginalFolder'
            ) d ON  d.Dummy = 0
    WHEN NOT MATCHED 
    THEN INSERT 
        (FolderId, FolderName)
        VALUES (newid(), 'copy_'+FolderName)
    OUTPUT  d.FolderId,
            INSERTED.FolderId
    INTO    @sFolder (FromFolderId, toFolderId);
    
    -- copy File structure
    MERGE   @FileIndex fi
    USING   (   SELECT  1 [Dummy],
                        fi.FileId, 
                        fi.[FileName]
                FROM    @FileIndex fi
                INNER
                JOIN    @FileFolder fm ON 
                        fi.FileId = fm.FileId
                INNER
                JOIN    @FolderIndex fo ON 
                        fm.FolderId = fo.FolderId
                WHERE   fo.FolderName = 'OriginalFolder'
            ) d ON  d.Dummy = 0
    WHEN NOT MATCHED 
    THEN INSERT ([FileName])
        VALUES ([FileName])
    OUTPUT  d.FileId,
            INSERTED.FileId
    INTO    @sFile (FromFileId, toFileId);
    
    -- link new files to Folders
    INSERT INTO @FileFolder (FileId, FolderId)
        SELECT  sfi.toFileId, sfo.toFolderId
        FROM    @FileFolder fm
        INNER
        JOIN    @sFile sfi ON  
                fm.FileId = sfi.FromFileId
        INNER
        JOIN    @sFolder sfo ON 
                fm.FolderId = sfo.FromFolderId
    -- return    
    SELECT  * 
    FROM    @FileIndex fi 
    JOIN    @FileFolder ff ON  
            fi.FileId = ff.FileId 
    JOIN    @FolderIndex fo ON  
            ff.FolderId = fo.FolderId
    
    0 讨论(0)
  • 2020-11-22 01:08

    I would like to add another example to add to @Nathan's example, as I found it somewhat confusing.

    Mine uses real tables for the most part, and not temp tables.

    I also got my inspiration from here: another example

    -- Copy the FormSectionInstance
    DECLARE @FormSectionInstanceTable TABLE(OldFormSectionInstanceId INT, NewFormSectionInstanceId INT)
    
    ;MERGE INTO [dbo].[FormSectionInstance]
    USING
    (
        SELECT
            fsi.FormSectionInstanceId [OldFormSectionInstanceId]
            , @NewFormHeaderId [NewFormHeaderId]
            , fsi.FormSectionId
            , fsi.IsClone
            , @UserId [NewCreatedByUserId]
            , GETDATE() NewCreatedDate
            , @UserId [NewUpdatedByUserId]
            , GETDATE() NewUpdatedDate
        FROM [dbo].[FormSectionInstance] fsi
        WHERE fsi.[FormHeaderId] = @FormHeaderId 
    ) tblSource ON 1=0 -- use always false condition
    WHEN NOT MATCHED
    THEN INSERT
    ( [FormHeaderId], FormSectionId, IsClone, CreatedByUserId, CreatedDate, UpdatedByUserId, UpdatedDate)
    VALUES( [NewFormHeaderId], FormSectionId, IsClone, NewCreatedByUserId, NewCreatedDate, NewUpdatedByUserId, NewUpdatedDate)
    
    OUTPUT tblSource.[OldFormSectionInstanceId], INSERTED.FormSectionInstanceId
    INTO @FormSectionInstanceTable(OldFormSectionInstanceId, NewFormSectionInstanceId);
    
    
    -- Copy the FormDetail
    INSERT INTO [dbo].[FormDetail]
        (FormHeaderId, FormFieldId, FormSectionInstanceId, IsOther, Value, CreatedByUserId, CreatedDate, UpdatedByUserId, UpdatedDate)
    SELECT
        @NewFormHeaderId, FormFieldId, fsit.NewFormSectionInstanceId, IsOther, Value, @UserId, CreatedDate, @UserId, UpdatedDate
    FROM [dbo].[FormDetail] fd
    INNER JOIN @FormSectionInstanceTable fsit ON fsit.OldFormSectionInstanceId = fd.FormSectionInstanceId
    WHERE [FormHeaderId] = @FormHeaderId
    
    0 讨论(0)
提交回复
热议问题