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.