SQL Server OUTPUT: capturar as alterações corretas
Obtenha chaves e valores anteriores e novos com OUTPUT, considerando ordem, triggers, falhas transacionais e correlação.
Atualizar linhas e consultá-las depois faz duas perguntas diferentes: quais linhas a instrução mudou e o que as linhas correspondentes contêm agora. Sob concorrência, essas respostas podem divergir. OUTPUT vincula o resultado à própria modificação, permitindo capturar chaves geradas e valores anteriores e novos com associação precisa.
Capturar uma relação estável
O exemplo usa tabelas temporárias e altera duas linhas de estoque. Ele captura chave, quantidade anterior e quantidade nova do mesmo UPDATE. O ORDER BY final organiza a apresentação sem depender da ordem física de atualização.
IF @@TRANCOUNT <> 0
THROW 50000, 'This example owns its transaction.', 1;
SET XACT_ABORT ON;
CREATE TABLE #Stock (ItemId int PRIMARY KEY, Qty int NOT NULL);
INSERT #Stock VALUES (1, 12), (2, 20);
CREATE TABLE #Changed (ItemId int, OldQty int, NewQty int);
BEGIN TRY
BEGIN TRAN;
UPDATE #Stock
SET Qty = Qty - 2
OUTPUT inserted.ItemId, deleted.Qty, inserted.Qty
INTO #Changed(ItemId, OldQty, NewQty)
WHERE ItemId IN (1, 2) AND Qty >= 2;
COMMIT;
SELECT ItemId, OldQty, NewQty FROM #Changed ORDER BY ItemId;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK;
THROW;
END CATCH;
Mantenha a chave na saída. Retornar apenas quantidades obriga o cliente a adivinhar a associação. Para inserções de várias linhas, preserve uma correlação única fornecida pelo cliente e devolva-a junto com a identidade gerada. Não associe a primeira identidade recebida à primeira entrada: essa ordem não é garantida.
Capture somente colunas necessárias. OUTPUT inserted.* acopla a API à estrutura inteira e pode copiar valores grandes sem necessidade. Uma lista explícita torna mudanças de tipos visíveis e evita exposição acidental de campos internos.
Separar saída de confirmação
A fronteira transacional continua decisiva. OUTPUT não comprova que a transação de negócio foi confirmada. Uma instrução posterior pode falhar, ocorrer rollback ou a conexão desaparecer durante a confirmação do commit. O aplicativo precisa consumir o resultado completo e seus erros antes de considerar a operação bem-sucedida.
O padrão captura em tabela temporária, confirma e só então devolve linhas. Se algo falhar, CATCH desfaz e propaga o erro em vez de selecionar uma resposta de sucesso. A verificação impede transação externa, pois o chamador ainda poderia desfazê-la depois de receber essa resposta.
Isso resolve a sequência local, não a perda de resposta. Se o commit terminar sem que o cliente receba o resultado, uma nova tentativa precisa de identificador durável para encontrar a operação anterior. A tabela temporária desaparece com a sessão. Grave correlação e resultado permanentemente quando a API precisar de escritas seguras para repetição.
Definir limites de triggers e auditoria
Os valores inserted de OUTPUT refletem a modificação antes dos triggers AFTER. Se um trigger normalizar algum valor depois, a saída pode diferir do conteúdo final. Determine qual contrato o cliente precisa. Para valores definitivos, capture chaves e planeje uma leitura final com isolamento adequado em uma transação claramente definida.
OUTPUT direto também possui restrições quando há triggers habilitados para a ação. OUTPUT INTO pode ser apropriado, mas seu destino tem limitações próprias. Verifique o esquema verdadeiro, não apenas uma tabela vazia de demonstração.
Uma resposta enviada ao cliente não é auditoria durável. Uma tabela de auditoria gravada na mesma transação acompanha alterações confirmadas, mas sua escrita também é desfeita no rollback. Registrar tentativas malsucedidas exige outro desenho. Diferencie alterações concluídas, tentativas e a necessidade eventual de ambas.
Por fim, meça o custo da captura em grandes modificações. Milhões de valores anteriores e novos podem consumir memória, log e rede. Uma resposta estreita com chave e estado pode atender melhor. Teste sucesso, falha forçada, valores alterados por trigger e correlação de várias entradas. Confira especialmente se o cliente descarta linhas já observadas quando um erro posterior invalida o resultado do comando, em vez de tratá-las como alterações confirmadas.
Referências técnicas: Microsoft Learn: OUTPUT · Microsoft Learn: TRY CATCH.