Mysql - Como sair / sair do procedimento armazenado


131

Eu tenho uma pergunta muito simples, mas não recebi nenhum código simples para sair do SP usando o Mysql. Alguém pode compartilhar comigo como fazer isso?

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;

1
Ou, você poderia usar IF tablename IS NOT NULL THEN...;)
OMG Pôneis

4
Eu estou tentando definir atalho ... caso contrário, eu tenho que codificar dentro da instrução IF, e esta não é a única instrução EXIT ... que você precisa da função exit, em vez disso, fazemos vários IF dentro do Stored Proc.
precisa saber é o seguinte

Respostas:


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;

1
Ótimo! Você até aponta que a END proc_label;sintaxe (mostrada na maioria dos exemplos oficiais do MySQL) não é necessária. (esta é uma ótima maneira de comentar uma proc armazenado sem ter que rolar para a parte inferior para colocar */no lugar)

2
você pode sair e retornar um valor?
Ygaradon

35
Basta rotular a seção BEGIN de cada processo 'this_proc'. Porque LEAVE this_proc;parece perfeito!
Senão

@ygaradon Os procedimentos armazenados não retornam valores. Você precisa usar uma função armazenada e return <value>retornar um valor.
David Harkness

1
Eu acho que o espaço é necessário entre :e BEGINcomo proc_label:BEGINdeu erro de sintaxe enquanto proc_label: BEGINtrabalhava.
Umair Malhi

13

Se você deseja uma "saída antecipada" para uma situação em que não houve erro, use a resposta aceita postada por @piotrm. Geralmente, no entanto, você estará pagando devido a uma condição de erro (especialmente em um procedimento SQL).

A partir do MySQL v5.5, você pode lançar uma exceção. Negar manipuladores de exceção, etc., que obterão o mesmo resultado, mas de uma maneira mais limpa e mais comovente.

Aqui está como:

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 "Condição de exceção definida pelo usuário sem tratamento". Por padrão, isso produzirá um código de erro de 1644(que tem o mesmo significado). Observe que você pode lançar outros códigos de condição ou de erro, se desejar (além de detalhes adicionais para o tratamento de exceções).

Para mais informações sobre esse assunto, confira:

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

Como gerar um erro dentro de uma função MySQL

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

Termo aditivo

Ao reler este post, percebi que tinha algo a acrescentar. Antes do MySQL v5.5, havia uma maneira de emular lançando uma exceção. Não é exatamente a mesma coisa, mas este era o análogo: crie um erro chamando um procedimento que não existe. Chame o procedimento com um nome que seja significativo para obter um meio útil para determinar qual era o problema. Quando o erro ocorrer, você verá a linha da falha (dependendo do seu contexto de execução).

Por exemplo:

CALL AttemptedToInsertSomethingInvalid;

Observe que quando você cria um procedimento, não há validação executada para essas coisas. Portanto, enquanto em algo como uma linguagem compilada, você nunca poderia chamar uma função que não estava lá, em um script como este simplesmente falhará no tempo de execução, que é exatamente o que é desejado neste caso!


1
Parece a resposta mais correta e completa para mim e era exatamente o que eu queria. Como o OP, tenho vários testes (validação de entrada) que preciso executar e não queria aninhar todos, portanto isso funciona bem para mim.
Fodagus 28/11

12

Para lidar com essa situação de maneira portátil (ou seja, funcionará em todos os bancos de dados porque não usa o rótulo Kung fu do MySQL), divida o procedimento em partes lógicas, desta forma:

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;

7
Yucks, por que não usar a primeira solução?
Pacerier

1
Gostaria de poder votar isso duas vezes. Só porque o SQL não é uma linguagem de programação real, não dá a ninguém uma desculpa para escrever mais de 200 linhas de código em um único procedimento.
Max Heiber 31/07

Esta resposta está totalmente errada ou estou faltando alguma coisa? Por que tem votos positivos? Claramente, existe uma maneira de conseguir isso, demonstrada pela solução aceita.
Jlh

@ jlh estava errado (texto corrigido agora) porque eu não sabia sobre a técnica de rótulo do mysql, mas o código não está errado - ele funcionará em qualquer banco de dados.
Bohemian

2

Por que não isso:

CREATE PROCEDURE SP_Reporting(IN tablename VARCHAR(20))
BEGIN
     IF tablename IS NOT NULL THEN
          #proceed the code
     END IF;
     # Do nothing otherwise
END;

7
O código é muito longo ... não posso usar isso ... Isso é apenas uma amostra.
Joe iJam

Não importa o tamanho, ele não será executado.
Stephen

Se você estiver preocupado com a indentação, apenas desanexe a seção inteira na ifdeclaração. É logicamente idêntico a um "retorno antecipado".
bobobobo

@obobobo, ele está dizendo que, no caso dele, faz muito mais sentido logicamente não religar a lógica em torno dessa limitação do sql.
Pacerier

1
Pode ser que ele tenha um login com muitas verificações "se x É NULL ENTÃO SETresult = -1". Você quer que REALMENTE pare de fazer as coisas. Reduz a complexidade do ifs. Menos {} anotado
borjab

2

Isso funciona para mim:

 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

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;
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.