MySQL - Jak wyjść / wyjść z procedury składowanej


134

Mam bardzo proste pytanie, ale nie otrzymałem żadnego prostego kodu do wyjścia z SP przy użyciu MySQL. Czy ktoś może mi powiedzieć, jak to zrobić?

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
Lub możesz użyć IF tablename IS NOT NULL THEN...;)
OMG Kucyki

5
Próbuję dobrze skrócić ... w przeciwnym razie muszę kodować wewnątrz instrukcji IF, a to nie jest jedyna instrukcja EXIT ... że yi potrzebuje funkcji wyjścia, zamiast tego wykonujemy wiele JEŻELI w przechowywanym procencie.
Joe Ijam

Dobry URL referencyjny: bytes.com/topic/mysql/answers/...
Avishek

Odpowiedzi:


210
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
Świetny! Zwracasz nawet uwagę, że END proc_label;składnia (pokazana w większości oficjalnych przykładów MySQL) nie jest potrzebna. (to świetny sposób na skomentowanie przechowywanego procesu bez konieczności przewijania do dołu w celu wprowadzenia */)

2
czy możesz wyjść i zwrócić wartość?
ygaradon

36
Po prostu oznacz sekcję BEGIN każdego proca „this_proc”. Ponieważ LEAVE this_proc;brzmi idealnie!
SNag

1
@David Harkness nie może przekazać tego do parametru out? Czy to nie zwraca wartości?
Ken

1
Myślę, że miejsce jest konieczne między :i, BEGINjak proc_label:BEGINpodał błąd składni podczas proc_label: BEGINpracy.
Umair Malhi

14

Jeśli chcesz „wcześniejszego wyjścia” w sytuacji, w której nie wystąpił błąd, użyj zaakceptowanej odpowiedzi przesłanej przez @piotrm. Najczęściej jednak wyskakuje błąd z powodu błędu (szczególnie w procedurze SQL).

Od wersji MySQL v5.5 możesz zgłosić wyjątek. Negowanie obsługi wyjątków itp., Które dadzą ten sam wynik, ale w czystszy, bardziej przejmujący sposób.

Oto jak:

DECLARE CUSTOM_EXCEPTION CONDITION FOR SQLSTATE '45000';

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

Uwaga SQLSTATE '45000'oznacza „Nieobsłużony warunek wyjątku zdefiniowanego przez użytkownika”. Domyślnie spowoduje to wyświetlenie kodu błędu 1644(co ma to samo znaczenie). Zauważ, że możesz zgłosić inne kody warunków lub kody błędów, jeśli chcesz (plus dodatkowe szczegóły dotyczące obsługi wyjątków).

Więcej na ten temat znajdziesz w:

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

Jak zgłosić błąd w funkcji MySQL

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

Uzupełnienie

Kiedy ponownie czytam ten post, zdałem sobie sprawę, że mam coś więcej do dodania. Przed MySQL v5.5 istniał sposób na emulację zgłaszania wyjątku. To nie jest dokładnie to samo, ale to był analog: Utwórz błąd, wywołując procedurę, która nie istnieje. Nazwij procedurę, używając nazwy, która jest znacząca, aby uzyskać przydatne środki umożliwiające określenie, na czym polegał problem. Gdy wystąpi błąd, zobaczysz linię niepowodzenia (w zależności od kontekstu wykonania).

Na przykład:

CALL AttemptedToInsertSomethingInvalid;

Zauważ, że kiedy tworzysz procedurę, na takich rzeczach nie jest wykonywana walidacja. Tak więc, podczas gdy w czymś takim jak język kompilowany nigdy nie można wywołać funkcji, której nie było, w takim skrypcie po prostu zakończy się niepowodzeniem w czasie wykonywania, co jest dokładnie tym, co jest pożądane w tym przypadku!


1
Wydaje mi się, że jest to dla mnie najbardziej poprawna, dokładna odpowiedź i była dokładnie tym, czego chciałem. Podobnie jak OP, mam kilka testów (sprawdzanie poprawności danych wejściowych), które muszę uruchomić i nie chciałem ich wszystkich zagnieżdżać, więc to działa dobrze dla mnie.
Fodagus

12

Aby poradzić sobie z tą sytuacją w sposób przenośny (tj. Będzie działać na wszystkich bazach danych, ponieważ nie używa etykiety MySQL Kung fu), podziel procedurę na części logiczne, takie jak ta:

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
Fuj, dlaczego nie użyć zamiast tego pierwszego rozwiązania?
Pacerier

2
Chciałbym móc dwukrotnie głosować. Tylko dlatego, że SQL nie jest prawdziwym językiem programowania, nie daje nikomu wymówki, by napisać ponad 200 linii kodu w jednej procedurze.
Max Heiber

Czy ta odpowiedź jest po prostu błędna, czy czegoś mi brakuje? Dlaczego ma pozytywne głosy? Oczywiście można to osiągnąć, czego dowodem jest przyjęte rozwiązanie.
jlh

@jlh było źle (tekst został poprawiony), ponieważ nie wiedziałem o technice etykiet mysql, ale kod nie jest zły - będzie działał, właściwie na każdej bazie danych.
Bohemian

2

Dlaczego nie to:

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
Kod jest bardzo długi ... nie mogę tego użyć ... To tylko przykład.
Joe Ijam

Bez względu na długość, nie zostanie wykonany.
Stephen,

Jeśli martwisz się wcięciem, po prostu cofnij wcięcie całej sekcji w ifinstrukcji. Jest to logicznie identyczne z „wczesnym powrotem”.
bobobobo

@bobobobo, Mówi, że w jego przypadku logicznie o wiele bardziej sensowne jest nie zmieniać logiki wokół tego ograniczenia sql.
Pacerier

1
Może ma login z wieloma sprawdzeniami "jeśli x JEST NULL, TO SETresult = -1". Chcesz, żeby NAPRAWDĘ przestało robić rzeczy. Zmniejsza złożoność ifs. Mniej {} annidated
borjab

2

To działa dla mnie:

 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;
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.