TRY...CATCH (Transact-SQL)

Se aplica a: SQL Server Azure SQL Database Azure SQL Managed Instance Azure Synapse Analytics Analytics Platform System (PDW) Punto de conexión de análisis SQL en Microsoft Fabric Almacenamiento en Microsoft Fabric

Implementa el control de errores para Transact-SQL similar al control de excepciones en los lenguajes C# y Visual C++. Un grupo de instrucciones Transact-SQL se puede incluir en un TRY bloque. Si se produce un error en el TRY bloque, el control normalmente se pasa a otro grupo de instrucciones que se incluye en un CATCH bloque.

Convenciones de sintaxis de Transact-SQL

Sintaxis

BEGIN TRY
    { sql_statement | statement_block }
END TRY
BEGIN CATCH
    [ { sql_statement | statement_block } ]
END CATCH
[ ; ]

Argumentos

sql_statement

Cualquier instrucción Transact-SQL.

statement_block

Cualquier grupo de instrucciones Transact-SQL en un lote o entre un BEGIN...END bloque.

Comentarios

Una TRY...CATCH construcción detecta todos los errores de ejecución que tienen una gravedad superior a 10 que no cierran la conexión de la base de datos.

Un TRY bloque debe ir seguido inmediatamente de un bloque asociado CATCH . La inclusión de cualquier otra instrucción entre las END TRY instrucciones y BEGIN CATCH genera un error de sintaxis.

Una TRY...CATCH construcción no puede abarcar varios lotes. Una TRY...CATCH construcción no puede abarcar varios bloques de instrucciones Transact-SQL. Por ejemplo, una TRY...CATCH construcción no puede abarcar dos BEGIN...END bloques de instrucciones Transact-SQL y no puede abarcar una IF...ELSE construcción.

Si no hay errores en el código que se incluye en un TRY bloque, cuando finaliza la última instrucción del TRY bloque, el control pasa a la instrucción inmediatamente después de la instrucción asociada END CATCH .

Si hay un error en el código que se incluye en un TRY bloque, el control pasa a la primera instrucción del bloque asociado CATCH . Cuando finaliza el código del CATCH bloque, el control pasa a la instrucción inmediatamente después de la END CATCH instrucción .

Nota:

Si la END CATCH instrucción es la última instrucción de un procedimiento almacenado o desencadenador, el control se devuelve a la instrucción que llamó al procedimiento almacenado o desencadenó el desencadenador.

Los errores atrapados por un CATCH bloque no se devuelven a la aplicación que realiza la llamada. Si se debe devolver cualquier parte de la información de error a la aplicación, el código del CATCH bloque debe hacerlo mediante mecanismos como SELECT conjuntos de resultados o las RAISERROR instrucciones y PRINT .

TRY...CATCH las construcciones se pueden anidar. TRY Un bloque o un CATCH bloque puede contener construcciones anidadasTRY...CATCH. Por ejemplo, un CATCH bloque puede contener una construcción insertada TRY...CATCH para controlar los errores detectados por el CATCH código.

Los errores encontrados en un CATCH bloque se tratan como errores generados en cualquier otro lugar. Si el CATCH bloque contiene una construcción anidada TRY...CATCH , cualquier error del bloque anidado TRY pasa el control al bloque anidado CATCH . Si no hay ninguna construcción anidada TRY...CATCH , el error se devuelve al autor de la llamada.

TRY...CATCH construye detectar errores no controladas a partir de procedimientos almacenados o desencadenadores ejecutados por el código del TRY bloque. Como alternativa, los procedimientos almacenados o desencadenadores pueden contener sus propias TRY...CATCH construcciones para controlar los errores generados por su código. Por ejemplo, cuando un TRY bloque ejecuta un procedimiento almacenado y se produce un error en el procedimiento almacenado, el error se puede controlar de las maneras siguientes:

  • Si el procedimiento almacenado no contiene su propia TRY...CATCH construcción, el error devuelve el control al CATCH bloque asociado al TRY bloque que contiene la EXECUTE instrucción .

  • Si el procedimiento almacenado contiene una TRY...CATCH construcción, el control de transferencia de errores al CATCH bloque del procedimiento almacenado. Cuando finaliza el código de CATCH bloque, el control se devuelve a la instrucción inmediatamente después de la EXECUTE instrucción que llamó al procedimiento almacenado.

GOTO Las instrucciones no se pueden usar para escribir un TRY bloque o CATCH . GOTO Las instrucciones se pueden usar para saltar a una etiqueta dentro del mismo TRY bloque o CATCH para dejar un TRY bloque o CATCH .

La TRY...CATCH construcción no se puede usar en una función definida por el usuario.

Recuperar información de error

En el ámbito de un CATCH bloque, se pueden usar las siguientes funciones del sistema para obtener información sobre el error que provocó la ejecución del CATCH bloque:

Función Descripción
ERROR_NUMBER Devuelve el número del error.
ERROR_SEVERITY Devuelve la gravedad.
ERROR_STATE Devuelve el número de estado de error.
ERROR_PROCEDURE Devuelve el nombre del procedimiento almacenado o desencadenador donde se produjo el error.
ERROR_LINE Devuelve el número de línea dentro de la rutina que provocó el error.
ERROR_MESSAGE Devuelve el texto completo del mensaje de error. El texto incluye los valores proporcionados para los parámetros sustituibles, como las longitudes, nombres de objeto o tiempos.

Estas funciones devuelven NULL si se llama fuera del ámbito del CATCH bloque. La información de error se puede recuperar mediante estas funciones desde cualquier parte del ámbito del CATCH bloque. Por ejemplo, en el siguiente script se muestra un procedimiento almacenado que contiene funciones de control de errores. Se llama al procedimiento almacenado en el bloque CATCH de una construcción TRY...CATCH y se devuelve información sobre el error.

-- Verify that the stored procedure does not already exist.
IF OBJECT_ID('usp_GetErrorInfo', 'P') IS NOT NULL
    DROP PROCEDURE usp_GetErrorInfo;
GO

-- Create procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
SELECT ERROR_NUMBER() AS ErrorNumber,
    ERROR_SEVERITY() AS ErrorSeverity,
    ERROR_STATE() AS ErrorState,
    ERROR_PROCEDURE() AS ErrorProcedure,
    ERROR_LINE() AS ErrorLine,
    ERROR_MESSAGE() AS ErrorMessage;
GO

BEGIN TRY
    -- Generate divide-by-zero error.
    SELECT 1 / 0;
END TRY

BEGIN CATCH
    -- Execute error retrieval routine.
    EXECUTE usp_GetErrorInfo;
END CATCH;

Las ERROR_* funciones también funcionan en un CATCH bloque dentro de un procedimiento almacenado compilado de forma nativa.

Errores no afectados por un TRY... Construcción CATCH

TRY...CATCH las construcciones no interceptan las condiciones siguientes:

  • Advertencias o mensajes informativos que tienen una gravedad 10 o inferior.

  • Errores que tienen la gravedad 20 o superior que detienen el procesamiento de las tareas de Motor de base de datos de SQL Server en la sesión. Si se produce un error que tiene una gravedad de 20 o superior y la conexión de base de datos no se interrumpe, TRY...CATCH controla el error.

  • Atenciones, como solicitudes de interrupción de clientes o conexiones de cliente interrumpidas.

  • Cuando un administrador del sistema usa la KILL instrucción para finalizar la sesión.

Los siguientes tipos de errores no se controlan mediante un CATCH bloque cuando se producen en el mismo nivel de ejecución que la TRY...CATCH construcción:

  • Errores de compilación, como errores de sintaxis, que impiden la ejecución de un lote.

  • Errores que se producen durante la recompilación de instrucciones, como errores de resolución de nombres de objeto que se producen después de la compilación debido a una resolución de nombres diferida.

  • Errores de resolución de nombres de objeto

Estos errores se devuelven al nivel de ejecución del lote, procedimiento almacenado o desencadenador.

Si se produce un error durante la compilación o la recompilación en el nivel de instrucción en un nivel de ejecución inferior (por ejemplo, al ejecutar sp_executesql o un procedimiento almacenado definido por el usuario) dentro del TRY bloque, el error se produce en un nivel inferior al de la TRY...CATCH construcción y lo controlará el bloque asociado CATCH .

En el ejemplo siguiente se muestra cómo la TRY...CATCH construcción no detecta un error de resolución de nombres de objeto generado por una SELECT instrucción, pero el bloque detecta CATCH cuando se ejecuta la misma SELECT instrucción dentro de un procedimiento almacenado.

BEGIN TRY
    -- Table does not exist; object name resolution
    -- error not caught.
    SELECT *
    FROM NonexistentTable;
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH

El error no se detecta y el control pasa de la TRY...CATCH construcción al siguiente nivel superior.

La ejecución de la SELECT instrucción dentro de un procedimiento almacenado hace que el error se produzca en un nivel inferior al TRY bloque. La construcción controla el TRY...CATCH error.

-- Verify that the stored procedure does not exist.
IF OBJECT_ID(N'usp_ExampleProc', N'P') IS NOT NULL
    DROP PROCEDURE usp_ExampleProc;
GO

-- Create a stored procedure that will cause an
-- object resolution error.
CREATE PROCEDURE usp_ExampleProc
AS
SELECT *
FROM NonexistentTable;
GO

BEGIN TRY
    EXECUTE usp_ExampleProc;
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;

Transacciones no confirmadas y XACT_STATE

Si un error generado en un TRY bloque hace que el estado de la transacción actual se invalide, la transacción se clasifica como una transacción no confirmada. Un error que normalmente finaliza una transacción fuera de un TRY bloque hace que una transacción escriba un estado no confirmable cuando se produce el error dentro de un TRY bloque. Una transacción sin confirmar solo puede realizar operaciones de lectura o .ROLLBACK TRANSACTION La transacción no puede ejecutar ninguna instrucción Transact-SQL que generaría una operación de escritura o .COMMIT TRANSACTION La XACT_STATE función devuelve un valor de -1 si una transacción se ha clasificado como una transacción no confirmable. Cuando finaliza el lote, Motor de base de datos revierte todas las transacciones activas no confirmables. Si no se envió ningún mensaje de error cuando la transacción entró en un estado no confirmable, cuando finaliza el lote, se envía un mensaje de error a la aplicación cliente. Esto indica que se ha detectado y revertido una transacción no confirmable.

Para obtener más información sobre las transacciones no confirmadas y la XACT_STATE función, consulte XACT_STATE.

Ejemplos

A Usar TRY...CATCH

En este ejemplo de código se muestra una instrucción SELECT que genera un error de división por cero. El error hace que la ejecución salte al bloque CATCH asociado.

BEGIN TRY
    -- Generate a divide-by-zero error.
    SELECT 1 / 0;
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO

B. Use TRY... CATCH en una transacción

En este ejemplo se muestra cómo funciona un bloque TRY...CATCH dentro de una transacción. La instrucción del bloque TRY genera un error por infracción de restricción.

BEGIN TRANSACTION;

BEGIN TRY
    -- Generate a constraint violation error.
    DELETE
    FROM Production.Product
    WHERE ProductID = 980;
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() AS ErrorState,
        ERROR_PROCEDURE() AS ErrorProcedure,
        ERROR_LINE() AS ErrorLine,
        ERROR_MESSAGE() AS ErrorMessage;

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO

C. Use TRY... CATCH con XACT_STATE

En este ejemplo se muestra cómo utilizar la construcción TRY...CATCH para controlar los errores que se producen en una transacción. La función XACT_STATE determina si la transacción debe confirmarse o revertirse. En este ejemplo SET XACT_ABORT es ON. Esto hace que la transacción sea no confirmable cuando se produce el error por infracción de restricción.

-- Check to see whether this stored procedure exists.
IF OBJECT_ID(N'usp_GetErrorInfo', N'P') IS NOT NULL
    DROP PROCEDURE usp_GetErrorInfo;
GO

-- Create procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
SELECT ERROR_NUMBER() AS ErrorNumber,
    ERROR_SEVERITY() AS ErrorSeverity,
    ERROR_STATE() AS ErrorState,
    ERROR_LINE() AS ErrorLine,
    ERROR_PROCEDURE() AS ErrorProcedure,
    ERROR_MESSAGE() AS ErrorMessage;
GO

-- SET XACT_ABORT ON will cause the transaction to be uncommittable
-- when the constraint violation occurs.
SET XACT_ABORT ON;

BEGIN TRY
    BEGIN TRANSACTION;

    -- A FOREIGN KEY constraint exists on this table. This
    -- statement will generate a constraint violation error.
    DELETE
    FROM Production.Product
    WHERE ProductID = 980;

    -- If the DELETE statement succeeds, commit the transaction.
    COMMIT TRANSACTION;
END TRY

BEGIN CATCH
    -- Execute error retrieval routine.
    EXECUTE usp_GetErrorInfo;

    -- Test XACT_STATE:
    -- If 1, the transaction is committable.
    -- If -1, the transaction is uncommittable and should
    --     be rolled back.
    -- XACT_STATE = 0 means that there is no transaction and
    --     a commit or rollback operation would generate an error.
    -- Test whether the transaction is uncommittable.
    IF (XACT_STATE()) = -1
    BEGIN
        PRINT N'The transaction is in an uncommittable state. Rolling back transaction.'

        ROLLBACK TRANSACTION;
    END;

    -- Test whether the transaction is committable.
    -- You may want to commit a transaction in a catch block if you want to commit changes to statements that ran prior to the error.
    IF (XACT_STATE()) = 1
    BEGIN
        PRINT N'The transaction is committable. Committing transaction.'

        COMMIT TRANSACTION;
    END;
END CATCH;
GO