Mysql - Cómo salir / salir del procedimiento almacenado

131

Tengo una pregunta muy simple pero no obtuve ningún código simple para salir de SP usando Mysql. ¿Alguien puede compartir conmigo cómo hacer eso?

CREATE PROCEDURE SP_Reporting(IN tablename VARCHAR(20))
BEGIN
     IF tablename IS NULL THEN
          #Exit this stored procedure here
     END IF;

     #proceed the code
END;
Joe Ijam
fuente
1
O bien, podría usar IF tablename IS NOT NULL THEN...;)
OMG Ponies
44
Estoy tratando de reducir el acceso directo ... de lo contrario, tengo que codificar dentro de la instrucción IF, y esta no es la única instrucción EXIT ... que necesito la función de salida, sino que hacemos múltiples IF dentro de Stored Proc.
Joe Ijam
Buena URL de referencia: bytes.com/topic/mysql/answers/…
Avishek

Respuestas:

204
CREATE PROCEDURE SP_Reporting(IN tablename VARCHAR(20))
proc_label:BEGIN
     IF tablename IS NULL THEN
          LEAVE proc_label;
     END IF;

     #proceed the code
END;
piotrm
fuente
1
¡Excelente! Incluso señala que la END proc_label;sintaxis (que se muestra en la mayoría de los ejemplos oficiales de MySQL) no es necesaria. (esto es una gran manera de crear un comentario en un procedimiento almacenado sin tener que desplazarse hasta la parte inferior de poner */en su lugar)
2
¿puedes irte y devolver un valor?
ygaradon
35
Simplemente etiquete la sección COMENZAR de cada proceso 'this_proc'. ¡Porque LEAVE this_proc;suena perfecto!
SNag 01 de
@ygaradon Los procedimientos almacenados no devuelven valores. Debe usar una función almacenada y return <value>devolver un valor.
David Harkness
1
Creo que el espacio es necesario entre :y BEGINcomo proc_label:BEGINdio error de sintaxis mientras se proc_label: BEGINtrabaja.
Umair Malhi
13

Si desea una "salida anticipada" para una situación en la que no hubo error, utilice la respuesta aceptada publicada por @piotrm. Sin embargo, lo más habitual es que esté rescatando debido a una condición de error (especialmente en un procedimiento SQL).

A partir de MySQL v5.5 puede lanzar una excepción. Negar los manejadores de excepciones, etc. que lograrán el mismo resultado, pero de una manera más limpia y conmovedora.

Así es cómo:

DECLARE CUSTOM_EXCEPTION CONDITION FOR SQLSTATE '45000';

IF <Some Error Condition> THEN      
    SIGNAL CUSTOM_EXCEPTION
    SET MESSAGE_TEXT = 'Your Custom Error Message';
END IF;     

Nota SQLSTATE '45000'equivale a "Condición de excepción definida por el usuario no controlada". Por defecto, esto producirá un código de error de 1644(que tiene el mismo significado). Tenga en cuenta que puede lanzar otros códigos de condición o códigos de error si lo desea (más detalles adicionales para el manejo de excepciones).

Para obtener más información sobre este tema, consulte:

https://dev.mysql.com/doc/refman/5.5/en/signal.html

Cómo generar un error dentro de una función MySQL

http://www.databasejournal.com/features/mysql/mysql-error-handling-using-the-signal-and-resignal-statements.html

Apéndice

Mientras releía esta publicación mía, me di cuenta de que tenía algo más que agregar. Antes de MySQL v5.5, había una forma de emular lanzando una excepción. No es exactamente lo mismo, pero este fue el análogo: cree un error llamando a un procedimiento que no existe. Llame al procedimiento por un nombre que sea significativo para obtener un medio útil para determinar cuál fue el problema. Cuando se produce el error, podrá ver la línea de falla (dependiendo del contexto de ejecución).

Por ejemplo:

CALL AttemptedToInsertSomethingInvalid;

Tenga en cuenta que cuando crea un procedimiento, no se realiza ninguna validación en tales cosas. Entonces, si bien en algo así como un lenguaje compilado, nunca se podría llamar a una función que no estaba allí, en un script como este simplemente fallará en tiempo de ejecución, ¡que es exactamente lo que se desea en este caso!

BuvinJ
fuente
1
Esto me parece la respuesta más correcta y exhaustiva, y fue exactamente lo que quería. Al igual que el OP, tengo varias pruebas (validación de entrada) que necesito ejecutar y no quería anidarlas a todas, así que esto funciona bien para mí.
Fodagus
12

Para manejar esta situación de manera portátil (es decir, funcionará en todas las bases de datos porque no usa la etiqueta de MySQL Kung fu), divida el procedimiento en partes lógicas, como esta:

CREATE PROCEDURE SP_Reporting(IN tablename VARCHAR(20))
BEGIN
     IF tablename IS NOT NULL THEN
         CALL SP_Reporting_2(tablename);
     END IF;
END;

CREATE PROCEDURE SP_Reporting_2(IN tablename VARCHAR(20))
BEGIN
     #proceed with code
END;
Bohemio
fuente
77
Yucks, ¿por qué no usar la primera solución en su lugar?
Pacerier 01 de
1
Ojalá pudiera votar esto dos veces. El hecho de que SQL no sea un lenguaje de programación real no le da a nadie una excusa para escribir más de 200 líneas de código en un solo procedimiento.
Max Heiber
¿Esta respuesta es simplemente incorrecta o me falta algo? ¿Por qué tiene votos a favor? Claramente, hay una manera de lograr esto que se demuestra con la solución aceptada.
jlh
@jlh estaba mal (texto corregido ahora) en que no sabía sobre la técnica de etiqueta de mysql, pero el código no está mal, funcionará en cualquier base de datos en realidad.
Bohemio
2

¿Por qué no esto?

CREATE PROCEDURE SP_Reporting(IN tablename VARCHAR(20))
BEGIN
     IF tablename IS NOT NULL THEN
          #proceed the code
     END IF;
     # Do nothing otherwise
END;
Stephen
fuente
77
El código es muy largo ... no puedo usar esto ... Eso es solo una muestra.
Joe Ijam
No importa la longitud, no se ejecutará.
Stephen
Si le preocupa la sangría, simplemente desinfecte toda la sección de la ifdeclaración. Es lógicamente idéntico a un "retorno temprano".
bobobobo
@bobobobo, está diciendo en su caso que lógicamente tiene mucho más sentido no volver a cablear la lógica en torno a esta limitación sql.
Pacerier 01 de
1
Es posible que tenga un inicio de sesión con muchas comprobaciones "si x ES NULO ENTONCES SETresult = -1". Usted quiere que REALMENTE deje de hacer cosas. Reduce la complejidad de ifs. Menos {} anidado
borjab
2

Esto funciona para mi:

 CREATE DEFINER=`root`@`%` PROCEDURE `save_package_as_template`( IN package_id int , 
IN bus_fun_temp_id int  , OUT o_message VARCHAR (50) ,
            OUT o_number INT )
 BEGIN

DECLARE  v_pkg_name  varchar(50) ;

DECLARE  v_pkg_temp_id  int(10)  ; 

DECLARE  v_workflow_count INT(10);

-- checking if workflow created for package
select count(*)  INTO v_workflow_count from workflow w where w.package_id = 
package_id ;

this_proc:BEGIN   -- this_proc block start here 

 IF  v_workflow_count = 0 THEN
   select 'no work flow ' as 'workflow_status' ;
    SET o_message ='Work flow is not created for this package.';
    SET  o_number = -2 ;
      LEAVE this_proc;
 END IF;

select 'work flow  created ' as 'workflow_status' ;
-- To  send some message
SET o_message ='SUCCESSFUL';
SET  o_number = 1 ;

  END ;-- this_proc block end here 

END
Devendra Singraul
fuente
0
MainLabel:BEGIN

IF (<condition>) IS NOT NULL THEN
    LEAVE MainLabel;
END IF; 

....code

i.e.
IF (@skipMe) IS NOT NULL THEN /* @skipMe returns Null if never set or set to NULL */
     LEAVE MainLabel;
END IF;
sdfor
fuente