Hey guys!
Primeiro post de 2019!
Nesse artigo, vou explicar a diferença entre @@ERROR e a função ERROR_NUMBER(), que em teoria, trazem o mesmo resultado, isto é, o número de erro causado por alguma operação na sessão atual. A ideia de escrever sobre isso, veio de uma dúvida de um Nigeriano no grupo SQL Server – DBA, do Telegram e achei que seria legal ter essa explicação publicada no meu blog para ajudar outras pessoas com a mesma dúvida.
Primeiramente, vamos consultar a documentação oficial da Microsoft para ver se temos alguma dica da diferença desses 2 métodos:
Retorna o número do erro da última instrução Transact-SQL executada. Retornará 0 se a instrução Transact-SQL anterior não tiver encontrado nenhum erro.
Uma vez que @@ERROR é apagado e redefinido em cada instrução executada, consulte-o imediatamente após a instrução ser verificada ou salve-o em uma variável local que possa ser verificada mais tarde.
Essa função retorna o número do erro que fez com que o bloco CATCH de um constructo TRY…CATCH fosse executado. Quando chamado em um bloco CATCH, ERROR_NUMBER retorna o número do erro que fez com que o bloco CATCH fosse executado. ERROR_NUMBER retorna NULL quando chamado fora do escopo de um bloco CATCH.
ERROR_NUMBER retorna um número de erro relevante, independentemente de quantas vezes ou de em que local ele é executado dentro do escopo do bloco CATCH. É diferente de uma função como @@ERROR, que retorna apenas um número de erro na instrução imediatamente após àquela que causa um erro.
Em um bloco CATCH aninhado, ERROR_NUMBER retorna o número do erro específico do escopo do bloco CATCH que referenciou esse bloco CATCH. Por exemplo, o bloco CATCH de um constructo TRY…CATCH externo poderia ter um constructo TRY…CATCH interno. Dentro desse bloco CATCH interno, ERROR_NUMBER retorna o número do erro que invocou o bloco CATCH interno. Se ERROR_NUMBER é executado no bloco CATCH externo, ele retorna o número do erro que invocou esse bloco CATCH externo.
Analisando a documentação, fica claro a diferença desses 2 métodos de identificação do código do erro:
- @@ERROR: Retorna o código de erro da última instrução executada (a cada nova instrução, a variável é zerada). Retorna 0 se não tiver erro ou se a variável for zerada. Recomenda-se atribuir o resultado do @@ERROR a uma variável local logo no início do CATCH, pois QUALQUER COMANDO faz com que o @@ERROR seja zerado (até mesmo um SELECT @@ERROR).
- ERROR_NUMBER: Retorna o código de erro dentro do escopo de um bloco CATCH. Retorna NULL se você tentar utilizar o comando fora de um bloco CATCH
E agora, vamos ver isso funcionando na prática!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
BEGIN TRY SELECT 1/0 END TRY BEGIN CATCH -- Os 2 comandos vão trazer o mesmo retorno SELECT ERROR_NUMBER() AS [ERROR_NUMBER_1], @@ERROR AS [@@ERROR_1] BEGIN TRY EXEC('SELECT * FROM dbo.Teste_123') END TRY BEGIN CATCH /* Aqui, vou colocar um comando PRINT para "atrapalhar" o comportamento do @@ERROR Como o @@ERROR é resetado a cada comando executado, o PRINT vai fazer com que a variável @@ERROR seja zerada */ PRINT 'Esse print vai atrapalhar o @@ERROR' SELECT ERROR_NUMBER() AS [ERROR_NUMBER_2], @@ERROR AS [@@ERROR_2] BEGIN TRY EXEC dbo.stpTeste END TRY BEGIN CATCH -- Aqui nada de novo também.. os 2 terão o mesmo retorno SELECT ERROR_NUMBER() AS [ERROR_NUMBER_3], @@ERROR AS [@@ERROR_3] -- Mas se eu tentar executar novamente o comando... o ERROR_NUMBER permanece igual, enquanto o @@ERROR já foi zerado SELECT ERROR_NUMBER() AS [ERROR_NUMBER_3_DENOVO], @@ERROR AS [@@ERROR_3_DENOVO] END CATCH END CATCH /* Já aqui, o ERROR_NUMBER vai retornar a mensagem de erro do bloco 1, que é o escopo atual do bloco CATCH Já a variável @@ERROR ficará vazia, pois outros comandos foram executados depois da última mensagem de erro */ SELECT ERROR_NUMBER() AS [ERROR_NUMBER_VOLTOU_PRO_1], @@ERROR AS [@@ERROR_ZERADO_PORQUE_OUTRO_COMANDO_JA_FOI_EXECUTADO] END CATCH -- Por fim, como o ERROR_NUMBER() não está dentro de nenhum bloco de CATCH com erro, retornará NULL e a @@ERROR retornará 0 SELECT ERROR_NUMBER() AS [ERROR_NUMBER_FINAL], @@ERROR AS [@@ERROR_FINAL] |
Mas e se eu não estiver utilizando TRY..CATCH e quiser capturar o código do erro? Posso utilizar qualquer um dos dois métodos ?
Resposta: NÃO! Se não estiver dentro de um bloco TRY.. CATCH, a função ERROR_NUMBER() irá retornar NULL, enquanto a variável @@ERROR irá retornar o código do erro (lembre-se das condições de uso da @@ERROR para evitar que ela seja zerada e você perca essa informação).
And that's it, folks!
Post bem curtinho e objetivo e espero que tenha ajudado a esclarecer a diferença entre @@ERROR e ERROR_NUMBER().
E lembrem-se: USEM TRY…CATCH!
Um bom 2019 pra vocês e até o próximo artigo!
Grande abraço!