Considere o seguinte código de exemplo mínimo, completo e verificável (veja dbfiddle aqui ):
CREATE TABLE [dbo].[test]
(
[i] bigint NOT NULL
identity(1,1)
PRIMARY KEY CLUSTERED
, [d] varchar(10) NOT NULL
);
GO
Com um INSTEAD OF INSERT, UPDATE
gatilho:
CREATE TRIGGER [dbo_test_trigger]
ON [dbo].[test]
INSTEAD OF INSERT, UPDATE
AS
BEGIN
IF ROWCOUNT_BIG() = 0 RETURN;
SET NOCOUNT ON;
MERGE INTO [dbo].[test] [target]
USING [inserted] [source] ON [target].[i] = [source].[i]
WHEN NOT MATCHED THEN
INSERT
(
[d]
)
VALUES
(
[source].[d]
)
WHEN MATCHED THEN
UPDATE
SET [target].[d] = [source].[d];
END;
GO
Estou executando um insert na tabela, na esperança de obter o valor da identidade inserida, porém o valor retornado é 0
:
DECLARE @output TABLE
(
[i] bigint NOT NULL
, [d] varchar(10) NOT NULL
);
INSERT INTO [dbo].[test]
(
[d]
)
OUTPUT
[inserted].[i]
, [inserted].[d]
INTO @output
(
[i]
, [d]
)
VALUES ('test');
/* shows [i] is 0 */
SELECT *
FROM @output;
/* shows [i] is 1 */
SELECT *
FROM [dbo].[test];
Os resultados são:
eu | d |
---|---|
0 | teste |
e
eu | d |
---|---|
1 | teste |
O resultado desejado seria que ambos os conjuntos de resultados correspondessem, mas isso não acontece.
O que estou fazendo de errado?
Eu vi isso, no entanto, que parece bem diferente, já que não estou usando nenhuma visualização. O gatilho está na mesa no meu exemplo.
O comportamento é confuso e mal documentado.
Costumava ser um pouco melhor documentado em INSTEAD OF INSERT Triggers (link para documentos do 2008 R2):
A explicação é que no momento em que os valores são capturados – antes do gatilho ser acionado – o SQL Server não pode saber quantas linhas serão realmente inseridas pelo gatilho. Ele não atribui valores de identidade antecipadamente e de alguma forma tenta combiná-los quando os resultados do gatilho são conhecidos.
A citação:
transmite o conceito geral. Isso não significa que os resultados retornados sejam exatamente iguais em todos os aspectos , como se a operação subjacente tivesse ocorrido. Isso simplesmente não é possível em todas as situações.
O parágrafo anterior diz (ênfase adicionada):
Nenhum valor de identidade é atribuído antes das
INSTEAD OF
ações ocorrerem, portanto eles não podem estar presentes noOUTPUT
conjunto.Pode ser útil lembrar que a operação inicial (INSERT neste exemplo) ocorre em uma tabela temporária oculta, apesar de estar rotulada nos planos de execução como a própria tabela de destino. Mais informações em meu artigo Coisas interessantes sobre gatilhos INSTEAD OF .
Está se comportando conforme documentado.
Citação relevante: cláusula OUTPUT (Transact-SQL)
Demonstração atualizada:
Resultado
Como a tabela temporária é visível no escopo aninhado, posso ver que a primeira saída é a externa (mesmo antes de o gatilho ser chamado.
Se você descomentar,
WHERE 1 = 0
poderá ver que os valores pretendidos são inseridos de qualquer maneira.