Combine OUTPUT inserted.id with value from selected row

后端 未结 2 980
囚心锁ツ
囚心锁ツ 2020-12-10 08:41

Running SQL Server 2014. How can I insert multiple rows from a table and combine the inserted data with the new IDs?

Let\'s look at a stripped-down exam

相关标签:
2条回答
  • 2020-12-10 09:14

    You can (ab)use MERGE with OUTPUT clause.

    MERGE can INSERT, UPDATE and DELETE rows. In our case we need only to INSERT. 1=0 is always false, so the NOT MATCHED BY TARGET part is always executed. In general, there could be other branches, see docs. WHEN MATCHED is usually used to UPDATE; WHEN NOT MATCHED BY SOURCE is usually used to DELETE, but we don't need them here.

    This convoluted form of MERGE is equivalent to simple INSERT, but unlike simple INSERT its OUTPUT clause allows to refer to the columns that we need. It allows to retrieve columns from both source and destination tables thus saving a mapping between old and new IDs.

    MERGE INTO [dbo].[Test]
    USING
    (
        SELECT [Data]
        FROM @Old AS O
    ) AS Src
    ON 1 = 0
    WHEN NOT MATCHED BY TARGET THEN
    INSERT ([Data])
    VALUES (Src.[Data])
    OUTPUT Src.ID AS OldID, inserted.ID AS NewID
    INTO @New(ID, [OtherID])
    ;
    

    Regarding your update and relying on the order of generated IDENTITY values.

    In the simple case, when [dbo].[Test] has IDENTITY column, then INSERT with ORDER BY will guarantee that the generated IDENTITY values would be in the specified order. See point 4 in Ordering guarantees in SQL Server. Mind you, it doesn't guarantee the physical order of inserted rows, but it guarantees the order in which IDENTITY values are generated.

    INSERT INTO [dbo].[Test] ([Data])
    SELECT [Data]
    FROM @Old
    ORDER BY [RowID]
    

    But, when you use the OUTPUT clause:

    INSERT INTO [dbo].[Test] ([Data])
    OUTPUT inserted.[ID] INTO @New
    SELECT [Data]
    FROM @Old
    ORDER BY [RowID]
    

    the rows in the OUTPUT stream are not ordered. At least, strictly speaking, ORDER BY in the query applies to the primary INSERT operation, but there is nothing there that says what is the order of the OUTPUT. So, I would not try to rely on that. Either use MERGE or add an extra column to store the mapping between IDs explicitly.

    0 讨论(0)
  • 2020-12-10 09:17

    Alas, the OUTPUT clause is not designed to output something not going into the target table (or coming from the table in the case of an update).

    If you modify Data to have a dummy column for the old id, then you can output it.

    In fact, if the table is not large, you could consider adding the column for the insert and then dropping it afterwards.

    0 讨论(0)
提交回复
热议问题