Saltar al contenido

Cómo agregar un Try / Catch al procedimiento almacenado de SQL

Este dilema se puede resolver de diferentes maneras, por lo tanto te dejamos la resolución más completa para nosotros.

Solución:

Ver TRY … CATCH (Transact-SQL)

 CREATE PROCEDURE [dbo].[PL_GEN_PROVN_NO1]        
       @GAD_COMP_CODE  VARCHAR(2) =NULL, 
       @@voucher_no numeric =null output 
       AS         
   BEGIN  

     begin try 
         -- your proc code
     end try

     begin catch
          -- what you want to do in catch
     end catch    
  END -- proc end

Transact-SQL es un poco más complicado que los bloques try / catch de C # o C ++, debido a la complejidad adicional de las transacciones. Un bloque CATCH tiene que comprobar la función xact_state () y decidir si puede comprometerse o tiene que retroceder. He cubierto el tema en mi blog y tengo un artículo que muestra cómo manejar correctamente las transacciones con un bloque try catch, incluidas las posibles transacciones anidadas: manejo de excepciones y transacciones anidadas.

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0   
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(),
                 @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
        return;
    end catch   
end

Manejo de errores con procedimientos almacenados de SQL

TRY/CATCH el manejo de errores puede tener lugar dentro o fuera de un procedimiento (o ambos). Los ejemplos siguientes demuestran el manejo de errores en ambos casos.

Si desea experimentar más, puede bifurcar la consulta en Stack Exchange Data Explorer.

(Esto usa un procedimiento almacenado temporal … no podemos crear regular SP está en SEDE, pero la funcionalidad es la misma).

--our Stored Procedure
create procedure #myProc as --we can only create #temporary stored procedures on SEDE. 
  begin
    BEGIN TRY
      print 'This is our Stored Procedure.'
      print 1/0                          --<-- generate a "Divide By Zero" error.
      print 'We are not going to make it to this line.'
    END TRY

    BEGIN CATCH
      print 'This is the CATCH block within our Stored Procedure:'
          + ' Error Line #'+convert(varchar,ERROR_LINE())
          + ' of procedure '+isnull(ERROR_PROCEDURE(),'(Main)')
      --print 1/0                        --<-- generate another "Divide By Zero" error.
        -- uncomment the line above to cause error within the CATCH ¹ 
    END CATCH
  end
go

--our MAIN code block:
BEGIN TRY
  print 'This is our MAIN Procedure.'
  execute #myProc  --execute the Stored Procedure
      --print 1/0                        --<-- generate another "Divide By Zero" error.
        -- uncomment the line above to cause error within the MAIN Procedure ²
  print 'Now our MAIN sql code block continues.'
END TRY

BEGIN CATCH
  print 'This is the CATCH block for our MAIN sql code block:'
          + ' Error Line #'+convert(varchar,ERROR_LINE())
          + ' of procedure '+isnull(ERROR_PROCEDURE(),'(Main)')
END CATCH

Aquí está el resultado de ejecutar el sql anterior como está:

This is our MAIN Procedure.
This is our Stored Procedure.
This is the CATCH block within our Stored Procedure: Error Line #5 of procedure #myProc
Now our MAIN sql code block continues.

¹ Descomentar la "línea de error adicional" del procedimiento almacenado CAPTURA bloque producirá:

This is our MAIN procedure.
This is our Stored Procedure.
This is the CATCH block within our Stored Procedure: Error Line #5 of procedure #myProc
This is the CATCH block for our MAIN sql code block: Error Line #13 of procedure #myProc

² Quitando el comentario de la "línea de error adicional" del PRINCIPAL procedimiento producirá:

This is our MAIN Procedure.
This is our Stored Pprocedure.
This is the CATCH block within our Stored Procedure: Error Line #5 of procedure #myProc
This is the CATCH block for our MAIN sql code block: Error Line #4 of procedure (Main)

Utilice un solo procedimiento para el manejo de errores

En cuanto al tema de los procedimientos almacenados y el manejo de errores, puede ser útil (y más ordenado) utilizar un único procedimiento almacenado dinámico para manejar errores para otros múltiples procedimientos o secciones de código.

He aquí un ejemplo:

--our error handling procedure
create procedure #myErrorHandling as
  begin
    print ' Error #'+convert(varchar,ERROR_NUMBER())+': '+ERROR_MESSAGE()  
    print ' occurred on line #'+convert(varchar,ERROR_LINE())
         +' of procedure '+isnull(ERROR_PROCEDURE(),'(Main)')
    if ERROR_PROCEDURE() is null       --check if error was in MAIN Procedure
      print '*Execution cannot continue after an error in the MAIN Procedure.'
  end
go

create procedure #myProc as     --our test Stored Procedure
  begin
    BEGIN TRY
      print 'This is our Stored Procedure.'
      print 1/0                       --generate a "Divide By Zero" error.
      print 'We will not make it to this line.'
    END TRY
    BEGIN CATCH
     execute #myErrorHandling
    END CATCH
  end
go

BEGIN TRY                       --our MAIN Procedure
  print 'This is our MAIN Procedure.'
  execute #myProc                     --execute the Stored Procedure
  print '*The error halted the procedure, but our MAIN code can continue.'
  print 1/0                           --generate another "Divide By Zero" error.
  print 'We will not make it to this line.'
END TRY
BEGIN CATCH
  execute #myErrorHandling
END CATCH

Salida de ejemplo: (Esta consulta se puede bifurcar en SEDE aquí).

This is our MAIN procedure.
This is our stored procedure.
 Error #8134: Divide by zero error encountered.
 occurred on line #5 of procedure #myProc
*The error halted the procedure, but our MAIN code can continue.
 Error #8134: Divide by zero error encountered.
 occurred on line #5 of procedure (Main)
*Execution cannot continue after an error in the MAIN procedure.

Documentación:

En el alcance de un TRY/CATCH bloque, las siguientes funciones del sistema se pueden utilizar para obtener información sobre el error que causó el CATCH bloque a ejecutar:

  • 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 ocurrió 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 cualquier parámetro sustituible, como longitudes, nombres de objetos o tiempos.

(Fuente)

Tenga en cuenta que hay dos tipos de errores de SQL: Terminal y Atrapable. TRY/CATCH voluntad [obviously] sólo detecta los errores "detectables". Esta es una de varias formas de aprender más sobre sus errores de SQL, pero probablemente sea la más útil.

Es "mejor fallar ahora" (durante el desarrollo) en comparación con más adelante porque, como dice Homer . . .

Te mostramos reseñas y puntuaciones

Acuérdate de que puedes permitirte decir si diste con la respuesta.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *