53

¿Cómo puedo salir en medio de un procedimiento almacenado?SQL Server 2000: ¿cómo salir de un procedimiento almacenado?

Tengo un procedimiento almacenado en el que quiero rescatar temprano (al intentar depurarlo). He intentado llamar RETURN y RAISERROR, y el SP se mantiene en marcha:

CREATE PROCEDURE dbo.Archive_Session @SessionGUID uniqueidentifier AS 

    print 'before raiserror' 
    raiserror('this is a raised error', 18, 1) 
    print 'before return' 
    return -1 
    print 'after return' 

[snip] 

Sé que sigue funcionando porque se produzca un error más abajo. No veo ninguna de mis impresiones. Si comento hacia fuera la mayor parte del procedimiento almacenado:

CREATE PROCEDURE dbo.Archive_Session @SessionGUID uniqueidentifier AS 

    print 'before raiserror' 
    raiserror('this is a raised error', 18, 1) 
    print 'before return' 
    return -1 
    print 'after return' 

    /* 
    [snip] 
    */ 

entonces no conseguir mi error, y ver los resultados:

before raiserror 
Server: Msg 50000, Level 18, State 1, Procedure Archive_Session, Line 5 
this is a raised error 
before return 

Entonces la pregunta es: ¿cómo rescatar a de un procedimiento almacenado en SQL Server?

+15

"Bienvenido al Hotel California ..." =) –

+0

Guh? (Relleno para hacer que mi consulta "Guh?" tenga al menos 15 caracteres) –

+7

Oh, espera, lo entiendo ... "nunca te puedes ir".

Respuesta

72

Puede utilizar RETURN para detener la ejecución de un procedimiento almacenado inmediatamente. Cita tomada de Books Online:

Sale incondicionalmente de una consulta o procedimiento. RETURN es inmediato y se completó y se puede usar en cualquier punto para salir de un bloque de instrucciones de procedimiento, lote o . Las declaraciones que siguen RETORNO no se ejecutan.

Fuera de paranoia, probé su ejemplo y muestra las IMPRESIONES y detiene la ejecución inmediatamente.

+1

¿Puede pensar en alguna razón por la cual llamar 'return' no saldría incondicionalmente de un procedimiento? –

+4

Sea cuidadoso al regresar de un procedimiento si ha iniciado una transacción o tiene un cursor abierto. –

+0

No puedo, ¿podría publicar un ejemplo completo de sproc que cuando lo ejecute, no salga inmediatamente en el RETORNO? Solo para que tengamos un ejemplo exacto para revisar – AdaTheDev

10

Ponlo en TRY/CATCH.

Cuando RAISERROR se ejecuta con una gravedad de 11 o superior en un bloque TRY, TI transfiere el control a la asociada bloque CATCH

Referencia: MSDN.

EDIT: Esto funciona para MSSQL 2005+, pero veo que ahora ha aclarado que está trabajando en MSSQL 2000. Lo dejo aquí para referencia.

+4

+1 SQL Server 2000, por lo que no ayuda a responder mi pregunta. Pero puede ser una técnica útil para alguien que intenta hacer manejo de excepciones –

+0

Me gusta mucho esto. pero ... suspiro ... algo más nuevo que aprender. –

27

A menos que especifique una gravedad de 20 o superior, raiserror no detendrá la ejecución. Vea el MSDN documentation.

La solución normal es incluir una return después de cada raiserror:

if @whoops = 1 
    begin 
    raiserror('Whoops!', 18, 1) 
    return -1 
    end 
+0

"Los niveles de gravedad del 19 al 25 solo pueden ser especificados por los miembros de la función de servidor fijo sysadmin o los usuarios con permisos ALTER TRACE". Desde MSDN –

+23

@Forgotten Semicolon: Sí, así que en la mayoría de los casos, 'raiserror' gana el premio por la función que funciona de una manera que nadie espera (así como el trofeo de oro) – Andomar

+1

+1. Realmente no es una respuesta a esta pregunta, pero "la respuesta es útil" –

4

Esto funciona aquí.

ALTER PROCEDURE dbo.Archive_Session 
    @SessionGUID int 
AS 
    BEGIN 
     SET NOCOUNT ON 
     PRINT 'before raiserror' 
     RAISERROR('this is a raised error', 18, 1) 
     IF @@Error != 0 
      RETURN 
     PRINT 'before return' 
     RETURN -1 
     PRINT 'after return' 
    END 
go 

EXECUTE dbo.Archive_Session @SessionGUID = 1 

devoluciones

before raiserror 
Msg 50000, Level 18, State 1, Procedure Archive_Session, Line 7 
this is a raised error 
+0

esto parece una manera más limpia/rápida de escribirlo. – JDPeckham

8

me di cuenta de por qué no se RETURN forma incondicional desde el procedimiento almacenado.El error que estoy viendo es mientras el procedimiento almacenado está siendo compilado - no cuando se está ejecutando.

Considere un procedimiento almacenado imaginaria:

CREATE PROCEDURE dbo.foo AS 

INSERT INTO ExistingTable 
EXECUTE LinkedServer.Database.dbo.SomeProcedure 

pesar de que este proedure stord contiene un error (tal vez es debido a que los objetos tienen un número differnet de columnas, tal vez hay una columna de marca de tiempo en la mesa, tal vez el el procedimiento almacenado no existe), aún puede guardar. Puede guardarlo porque está haciendo referencia a un servidor vinculado.

Pero cuando realmente se ejecuta el procedimiento almacenado, SQL Server a continuación, compila , y genera un plan de consulta.

Mi error es no sucediendo en la línea 114, es en la línea 114. SQL Server no puede compilar el procedimiento almacenado, es por eso que está fallando.

Y es por eso que RETURN no regresa, porque ni siquiera comenzó todavía.

+1

por supuesto, nunca debe codificar una inserción sin especificar las columnas. – HLGEM

+1

Por supuesto, quería codificar la inserción sin especificar columnas. Ahora que tengo que especificarlos, se perderán columnas adicionales añadidas a la tabla fuente. –

1

Es porque no tiene BEGIN y END declaraciones. No debería ver las impresiones o errores que ejecutan esta declaración, solo Statement Completed (o algo así).

4

Esto parece una gran cantidad de código, pero la mejor manera que he encontrado para hacerlo.

ALTER PROCEDURE Procedure 
    AS 

    BEGIN TRY 
     EXEC AnotherProcedure 
    END TRY 
    BEGIN CATCH 
     DECLARE @ErrorMessage NVARCHAR(4000); 
     DECLARE @ErrorSeverity INT; 
     DECLARE @ErrorState INT; 

     SELECT 
      @ErrorMessage = ERROR_MESSAGE(), 
      @ErrorSeverity = ERROR_SEVERITY(), 
      @ErrorState = ERROR_STATE(); 

     RAISERROR (@ErrorMessage, -- Message text. 
        @ErrorSeverity, -- Severity. 
        @ErrorState -- State. 
        ); 
     RETURN --this forces it out 
    END CATCH 

--Stuff here that you do not want to execute if the above failed.  

    END --end procedure 
Cuestiones relacionadas