MySQL - Beenden / Beenden der gespeicherten Prozedur

131

Ich habe eine sehr einfache Frage, aber ich habe keinen einfachen Code zum Beenden von SP mit MySQL erhalten. Kann mir jemand mitteilen, wie das geht?

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
quelle
1
Oder Sie könnten verwenden IF tablename IS NOT NULL THEN...;)
OMG Ponys
4
Ich versuche, eine Abkürzung zu finden ... ansonsten muss ich in der IF-Anweisung codieren, und dies ist nicht die einzige EXIT-Anweisung ... dass Sie eine Exit-Funktion benötigen, stattdessen führen wir mehrere IF in Stored Proc aus.
Joe Ijam
Gute Referenz-URL: bytes.com/topic/mysql/answers/…
Avishek

Antworten:

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
quelle
1
Toll! Sie weisen sogar darauf hin, dass die END proc_label;Syntax (in den meisten offiziellen MySQL-Beispielen gezeigt) nicht benötigt wird. (Dies ist eine großartige Möglichkeit, einen gespeicherten Prozess zu kommentieren, ohne nach unten scrollen zu müssen, um ihn */
2
Können Sie einen Wert verlassen und zurückgeben?
Ygaradon
35
Beschriften Sie einfach den Abschnitt BEGIN jedes Prozesses mit 'this_proc'. Weil es LEAVE this_proc;perfekt klingt!
SNag
@ygaradon Gespeicherte Prozeduren geben keine Werte zurück. Sie müssen eine gespeicherte Funktion verwenden und return <value>einen Wert zurückgeben.
David Harkness
1
Ich denke, zwischen :und BEGINals proc_label:BEGINSyntaxfehler während der proc_label: BEGINArbeit ist Platz notwendig .
Umair Malhi
13

Wenn Sie eine "vorzeitige Beendigung" für eine Situation wünschen, in der kein Fehler aufgetreten ist, verwenden Sie die akzeptierte Antwort von @piotrm. In der Regel werden Sie jedoch aufgrund einer Fehlerbedingung (insbesondere in einer SQL-Prozedur) gerettet.

Ab MySQL v5.5 können Sie eine Ausnahme auslösen. Negieren von Ausnahmebehandlungsroutinen usw., die das gleiche Ergebnis erzielen, jedoch sauberer und ergreifender.

Hier ist wie:

DECLARE CUSTOM_EXCEPTION CONDITION FOR SQLSTATE '45000';

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

Hinweis SQLSTATE '45000'entspricht "Nicht behandelte benutzerdefinierte Ausnahmebedingung". Standardmäßig wird ein Fehlercode von erzeugt1644 (der dieselbe Bedeutung hat) erzeugt. Beachten Sie, dass Sie bei Bedarf andere Bedingungscodes oder Fehlercodes auslösen können (plus zusätzliche Details für die Ausnahmebehandlung).

Weitere Informationen zu diesem Thema finden Sie unter:

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

So lösen Sie einen Fehler in einer MySQL-Funktion aus

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

Nachtrag

Als ich meinen Beitrag noch einmal las, wurde mir klar, dass ich noch etwas hinzufügen musste. Vor MySQL v5.5 gab es eine Möglichkeit, das Auslösen einer Ausnahme zu emulieren. Es ist nicht genau dasselbe, aber dies war das Analoge: Erstellen Sie einen Fehler, indem Sie eine Prozedur aufrufen, die nicht existiert. Rufen Sie die Prozedur unter einem aussagekräftigen Namen auf, um ein nützliches Mittel zu erhalten, mit dem Sie das Problem ermitteln können. Wenn der Fehler auftritt, wird die Fehlerzeile angezeigt (abhängig von Ihrem Ausführungskontext).

Beispielsweise:

CALL AttemptedToInsertSomethingInvalid;

Beachten Sie, dass beim Erstellen einer Prozedur keine Validierung für solche Dinge durchgeführt wird. Während Sie in so etwas wie einer kompilierten Sprache niemals eine Funktion aufrufen könnten, die nicht vorhanden war, schlägt sie in einem Skript wie diesem einfach zur Laufzeit fehl, was genau das ist, was in diesem Fall gewünscht wird!

BuvinJ
quelle
1
Dies scheint mir die richtigste und gründlichste Antwort zu sein und war genau das, was ich wollte. Wie das OP habe ich mehrere Tests (Eingabevalidierung), die ich ausführen muss, und ich wollte sie nicht alle verschachteln, daher funktioniert dies gut für mich.
Fodagus
12

Um diese Situation auf tragbare Weise zu handhaben (dh auf allen Datenbanken zu funktionieren, da das MySQL-Label Kung Fu nicht verwendet wird), teilen Sie die Prozedur wie folgt in logische Teile auf:

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;
Böhmisch
quelle
7
Yucks, warum nicht stattdessen die erste Lösung verwenden?
Pacerier
1
Ich wünschte, ich könnte dies zweimal abstimmen. Nur weil SQL keine echte Programmiersprache ist, gibt es für niemanden eine Entschuldigung, mehr als 200 Codezeilen in einer einzigen Prozedur zu schreiben.
Max Heiber
Ist diese Antwort einfach falsch oder fehlt mir etwas? Warum hat es positive Stimmen? Es gibt eindeutig einen Weg, dies zu erreichen, der durch die akzeptierte Lösung demonstriert wird.
21.
@jlh es war falsch (Text jetzt korrigiert), da ich nichts über die Etikettentechnik von mysql wusste, aber der Code ist nicht falsch - es wird auf jeder Datenbank funktionieren.
Böhmisch
2

Warum nicht das:

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
quelle
7
Der Code ist sehr lang ... ich kann ihn nicht verwenden ... Das ist nur ein Beispiel.
Joe Ijam
Unabhängig von der Länge wird es nicht ausgeführt.
Stephen
Wenn Sie sich Gedanken über das Einrücken machen, entfernen Sie einfach den gesamten Abschnitt in der ifAnweisung. Es ist logisch identisch mit einer "frühen Rückkehr".
Bobobobo
@bobobobo, er sagt in seinem Fall, dass es logisch viel sinnvoller ist, die Logik um diese SQL-Einschränkung nicht neu zu verdrahten.
Pacerier
1
Möglicherweise hat er ein Login mit vielen Überprüfungen "wenn x NULL ist, dann SETresult = -1". Sie möchten, dass es WIRKLICH aufhört, Dinge zu tun. Es reduziert die Komplexität von Wenns. Weniger {} annidiert
Borjab
2

Das funktioniert bei mir:

 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
quelle
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
quelle