Tratando erros no SQL
Como sabemos e temos visto por aqui, a linguagem SQL é bastante versátil com diversas formas de resolver um problema qualquer. Mas, será que essa versatilidade se estende quando queremos tratar sobre erros??
Sempre que estamos desenvolvendo uma query ou uma procedure, muitas vezes não nos atentamos a comportamentos indesejados em sua execução e, dependendo do tipo de comportamento, pode ser frustrante e problemático a falha na execução e pior, não saber por onde começar a corrigir o problema.
Desse modo, irei abordar no post de hoje uma maneira simples de criar um tratamento de erros dentro da sua procedure ou qualquer outra transação ganhando um maior controle sobre a execução do bloco de comando.
Os blocos de Try..Catch
Para começarmos a tratar qualquer comportamento inesperado, precisamos executar um determinado comando, certo? Para o SQL, ele precisa tentar a execução para após, começar o tratamento, caso haja falha.
Assim como utilizamos o try_cast ou Try_convert, para erros vamos passar o begin try e begin catch. Veja este primeiro exemplo.
Como percebemos na execução da transação, o SQL Server retornou de forma consistente o resultado e printou a mensagem informando que não há erro na divisão, evitando o bloco catch. Agora, perceba quando executamos a divisão por zero.
Como o SQL Server detectou um erro na transação, ele automaticamente pulou para o bloco de captura, o Catch. Como nosso bloco apenas printou a mensagem, podemos ver essa ação na imagem.
Um outro exemplo de tratamento dentro de uma transação pode ser visto abaixo. Primeiro, crie uma tabela de exemplo e após a tabela, um comando de insert.
Abaixo o bloco de comando. O primeiro insert com ID 1, respeita a constraint da coluna EMPID que deve ser maior que 0, porém, não ocorre com o segundo insert o que acarreta falha na transação.
Veja que o SQL Server chega a inserir uma linha, mas como no bloco de captura há um rollback para não afetar a integridade do banco, toda a transação do Try é encerrada.
Agora veja que corrigindo a transação toda a batch de comando é executada com sucesso.
Ainda que o try..catch auxilie no tratamento de erros, existe uma certa limitação com esse bloco principalmente quando executado em procedure. O que ocorre é que ele não consegue lidar com erros de compilação, veja esse exemplo.
Note que nesse exemplo utilizei uma tabela que não existe para simular uma falha de compilação. O begin try mesmo informando que há um erro, não passou para o bloco de catch retornando apenas que a tabela não existe.
Como podemos ver, essa é uma falha do try..catch. Uma forma de contornar, seria:
Quando passamos a procedure criada no exemplo anterior para ser executada por outra procedure (aninhamento) temos o seguinte resultado.
Assim, solucionamos o tratamento de erro quando temos problemas com compilação de procedures ou qualquer outro bloco SQL.
Até o momento o tratamento de erro foi elaborado apenas para situações controladas ou erros previsíveis e por ter esse tipo de ambiente, é plausível utilizar print como forma de ‘tratamento’. Agora, e em ambientes de produção onde uma procedure de rotina é executada diariamente e temos um horizonte de eventos para tratar, como deveríamos construir nossa solução?
Error Handling com SQL
A linguagem T-SQL dentro da sua gama de soluções possui alguns funções internas que retornam causas e consequências que ocorreram em erros de execução e a grande maioria é o rollback das transações, principalmente em procedure.
Essas mensagens são de extrema importância para tratar justamente dos erros que não controlamos ou foram inesperados. São elas:
São seis funções diferentes que o sql server possui para serem utilizadas no que tange ao tratamento.
- Error_message – mensagem de erro
- Error_number – número do erro
- Error_severity – grau de seriedade do erro
- Error_state – retorna qual o estado do erro que pode ter valores entre 1 e 255
- Error_line – linha que ocorreu ou iniciou o erro de execução
- Error_procedure – se houver várias procs aninhadas, informa qual procedure houve falha de execução
Para que essas funções informem o erro na execução de procedure por exemplo, elas devem vir no bloco de captura (catch). Veja abaixo:
Veja que a informação do erro na query vem completa, inclusive, mostrando em qual procedure houve falha.
Existe uma forma mais simples de executar esse tratamento que é colocando em uma outra procedure para ser chamada no bloco do catch, veja.
Uma vez criado esta procedure de captura de erro, veja como utilizar.
Note que no catch bastou apenas passar a procedure e executar. O erro foi retornado normalmente, como no exemplo anterior.
Conclusão
Este foi o post introdutório sobre a condução de erros que podem ser usadas em consultas e procedimentos. Elas retornam informações que podem servir de parâmetros para entender o que está acontecendo com sua execução.
É considerado uma boa prática que toda procedure possua esse tipo de tratamento para não perder nenhuma informação quanto a sua execução falha.
Use sempre uma procedure com as funções de erro para facilitar o trabalho e não perder ou esquecer alguma função e faltar informação.
Espero que tenham gostado, bom dia!
Link para o script.