Como você recupera o valor de identidade de uma linha inserida quando essa linha é inserida a partir OUTPUT
de uma UPDATE
instrução? Nem @@IDENTITY
nem SCOPE_IDENTITY()
parece estar definido corretamente.
Considere este código:
DECLARE @UpdateTable table (UpdateTableID int IDENTITY, UpdateTableValue int);
DECLARE @InsertTable table (InsertTableID int IDENTITY, UpdateTableValue1 int, UpdateTableValue2 int);
DECLARE @TestValue int = 5;
INSERT INTO @UpdateTable (UpdateTableValue) VALUES (1),(2),(3);
SELECT [@@IDENTITY] = @@IDENTITY, [SCOPE_IDENTITY()] = SCOPE_IDENTITY();
INSERT INTO @InsertTable (UpdateTableValue1, UpdateTableValue2)
SELECT
UpdateTableValue1, UpdateTableValue2
FROM (
UPDATE @UpdateTable
SET UpdateTableValue = UpdateTableValue + @TestValue
OUTPUT deleted.UpdateTableValue, inserted.UpdateTableValue
WHERE UpdateTableID = 2
) AS UpdateResults (UpdateTableValue1, UpdateTableValue2);
SELECT [@@IDENTITY] = @@IDENTITY, [SCOPE_IDENTITY()] = SCOPE_IDENTITY();
A última linha inserida tem um valor de identidade de 1, mas as funções @@IDENTITY
e SCOPE_IDENTITY()
estão retornando seus valores originais do original INSERT
antes da última instrução executada.
@@VERSION
:
Microsoft SQL Azure (RTM) - 12.0.2000.8 2 de maio de 2019 20:11:13 Copyright (C) 2019 Microsoft Corporation
Eu acredito que isso é porque
@@IDENTITY
eSCOPE_IDENTITY()
não funciona quando usado em combinação com umaUPDATE
declaração. Embora eu entenda que a resposta natural a isso seria "Bem, por que não retorna o ID do INSERT externo?" a resposta é: por causa do Escopo.A
UPDATE
instrução e aINSERT
instrução (usando os resultados doOUTPUT
) são executadas como uma instrução e estão inerentemente dentro do mesmo escopo uma da outra. Quando o mecanismo executa a consulta, ele percebe isso e, portanto, não consegue rastrear a identidade gerada pelo arquivoINSERT
. Você pode provar isso executando a seguinte consulta que divide theUPDATE
e theINSERT
em duas instruções individuais:O que produz os resultados corretos:
Se você precisar obter a identidade da tabela, você tem 3 opções até onde eu vejo:
OUTPUT
cláusula ao finalINSERT
para capturar o ID gerado.IDENT_CURRENT()
função para obter o valor atual.Se você estiver usando tabelas temporárias (não tabelas temporárias globais),
IDENT_CURRENT()
tudo bem, pois você pode garantir que ele retornará apenas o valor gerado dentro de sua sessão (já que os objetos não estão disponíveis por meio de outras sessões). No entanto, se o exemplo que você deu é apenas isso, eu usaria a opção 2 e usaria outraOUTPUT
cláusula para capturar o valor de identidade gerado:Isso então gera o valor correto: