El manejo de errores y la organización de registros en SQL han ganado especial popularidad con el desarrollo de procesos empresariales complejos, cuando se volvió importante no solo detener la ejecución en caso de error, sino registrar el hecho del fallo y, de ser posible, continuar trabajando. Originalmente, SQL no tenía herramientas desarrolladas de try-catch, y cada SGBD ofrecía sus propios mecanismos.
Historia de la cuestión:
Las versiones tempranas de los estándares SQL no tenían operadores incorporados para capturar errores en procedimientos. Posteriormente, los fabricantes comenzaron a implementar construcciones, como TRY...CATCH en Microsoft SQL Server, o HANDLER en MySQL, permitiendo un control más flexible del proceso de trabajo directamente en el nivel de la base de datos.
Problema:
Los errores pueden surgir tanto por datos incorrectos como por razones sistémicas. Si en el procedimiento almacenado no se implementa la captura y registro de errores, la depuración y el soporte se vuelven extremadamente difíciles. Además, es necesario poder distinguir entre errores críticos y errores manejados, para no interrumpir la ejecución de la operación empresarial donde no es necesario.
Solución:
En sistemas modernos, se deben implementar estructuras de captura y registro de errores. Es necesario crear tablas de registro separadas, utilizar TRY...CATCH (SQL Server) o DECLARE ... HANDLER (MySQL), almacenar información detallada sobre excepciones para luego analizar las causas de los fallos.
Ejemplo de código (SQL Server):
CREATE PROCEDURE dbo.UpdateCustomer @CustomerID INT, @NewName NVARCHAR(100) AS BEGIN BEGIN TRY UPDATE Customers SET Name = @NewName WHERE CustomerID = @CustomerID; END TRY BEGIN CATCH INSERT INTO ErrorLog (ErrorMessage, ErrorSeverity, ErrorTime) VALUES (ERROR_MESSAGE(), ERROR_SEVERITY(), GETDATE()); THROW; END CATCH END;
Características clave:
¿Se pueden capturar todos los tipos de errores dentro del bloque TRY...CATCH (o a través de un handler)?
No, no todos los errores, por ejemplo, fallos graves del servidor, pueden ser interceptados. Errores tipo "Attention," o fallo de conexión, están fuera del alcance del manejo de transacciones.
¿Qué ocurrirá con los cambios no confirmados en el procedimiento en caso de error, si no se utiliza una transacción?
Los cambios se registrarán parcialmente, parte de las actualizaciones entrará en la base de datos y parte puede perderse. Para evitar inconsistencias, se recomienda usar siempre transacciones.
BEGIN TRY BEGIN TRANSACTION; --...código COMMIT; END TRY BEGIN CATCH ROLLBACK; END CATCH
¿Se puede usar INSERT EXEC directamente desde el bloque CATCH para registrar el error de otro contexto?
No siempre: INSERT EXEC está prohibido en varios contextos (por ejemplo, si ya hay una transacción activa), por lo que esto puede causar errores de segundo nivel. Es mejor recopilar los detalles del error localmente y luego registrarlos con un solo INSERT.
El cliente implementó la lógica solo a través de RAISERROR sin registro, por lo que los errores no se guardaron ni se analizaron.
Ventajas:
Desventajas:
Se usó TRY...CATCH más la tabla ErrorLog, registrando tiempo, código de error, usuario, texto y traza.
Ventajas:
Desventajas: