Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Combine OUTPUT insert.id com o valor da linha selecionada


Você pode (ab) usar MERGE com OUTPUT cláusula.

MERGE pode INSERT , UPDATE e DELETE linhas. No nosso caso, precisamos apenas INSERT .1=0 é sempre falso, então NOT MATCHED BY TARGET parte é sempre executada. Em geral, pode haver outras ramificações, veja docs.WHEN MATCHED geralmente é usado para UPDATE;WHEN NOT MATCHED BY SOURCE é normalmente usado para DELETE , mas não precisamos deles aqui.

Esta forma complicada de MERGE é equivalente ao simples INSERT ,mas ao contrário do simples INSERT sua OUTPUT A cláusula permite fazer referência às colunas que precisamos. Permite recuperar colunas das tabelas de origem e destino, salvando assim um mapeamento entre os IDs antigos e novos.
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])
;

Em relação à sua atualização e contando com a ordem de IDENTITY gerada valores.

No caso simples, quando [dbo].[Test] tem IDENTITY coluna e, em seguida, INSERT com ORDER BY vai garantir que a IDENTITY gerada valores estariam na ordem especificada. Consulte o ponto 4 em Garantias de pedidos no SQL Server . Lembre-se, ele não garante a ordem física das linhas inseridas, mas garante a ordem em que IDENTITY valores são gerados.
INSERT INTO [dbo].[Test] ([Data])
SELECT [Data]
FROM @Old
ORDER BY [RowID]

Mas, quando você usa o OUTPUT cláusula:
INSERT INTO [dbo].[Test] ([Data])
OUTPUT inserted.[ID] INTO @New
SELECT [Data]
FROM @Old
ORDER BY [RowID]

as linhas no OUTPUT fluxo não são ordenados. Pelo menos, estritamente falando, ORDER BY na consulta se aplica ao INSERT principal operação, mas não há nada lá que diga qual é a ordem do OUTPUT . Então, eu não tentaria confiar nisso. Ou use MERGE ou adicione uma coluna extra para armazenar explicitamente o mapeamento entre os IDs.