Mysql - Як закрити / вийти зі збереженої процедури


131

У мене дуже просте запитання, але я не отримав простого коду для виходу з SP за допомогою Mysql. Хтось може поділитися зі мною, як це зробити?

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
Або ви можете використати IF tablename IS NOT NULL THEN...;)
OMG Ponies

4
Я намагаюся чітко визначити короткий скорочення ... інакше мені доведеться кодувати всередині оператора IF, і це не єдине твердження EXIT ... що yi потрібна функція виходу, а замість цього ми робимо декілька IF в Stored Proc.
Джо Іджам

Хороша довідкова URL-адреса: bytes.com/topic/mysql/answers/…
Avishek

Відповіді:


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
Чудово! Ви навіть зазначаєте, що END proc_label;синтаксис (показаний у більшості офіційних прикладів MySQL) не потрібен. (це чудовий спосіб коментувати збережену програму, не */

2
ви можете залишити і повернути значення?
ygaradon

35
Просто позначте розділ BEGIN кожного proc "this_proc". Бо LEAVE this_proc;звучить ідеально!
SNag

@ygaradon Збережені процедури не повертають значення. Потрібно використовувати збережену функцію та return <value>повернути значення.
Девід Харкнесс

1
Я думаю, що простір між :і BEGINяк proc_label:BEGINдав синтаксичну помилку, proc_label: BEGINпрацюючи.
Umair Malhi

13

Якщо ви хочете "дострокового виходу" для ситуації, в якій помилки не було, скористайтеся прийнятою відповіддю, опублікованою @piotrm. Найчастіше, однак, ви будете порушені через стан помилки (особливо в процедурі SQL).

Станом на MySQL v5.5 ви можете викинути виняток. Не заперечуючи обробників винятків тощо, які дозволять досягти такого ж результату, але більш чітким і більш гострим чином.

Ось як:

DECLARE CUSTOM_EXCEPTION CONDITION FOR SQLSTATE '45000';

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

Примітка SQLSTATE '45000'прирівнюється до "Умови виключення, визначеної користувачем". За замовчуванням це створить код помилки 1644(який має те саме значення). Зауважте, що ви можете кидати інші коди умов або коди помилок, якщо хочете (плюс додаткові дані для обробки винятків).

Щоб дізнатися більше про цю тему, перегляньте:

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

Як підняти помилку в рамках функції MySQL

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

Додаток

Під час перечитування цієї публікації я зрозумів, що я маю щось додатково додати. До MySQL v5.5 існував спосіб емуляції викиду винятку. Це не те саме, але це був аналог: Створіть помилку, викликавши процедуру, яка не існує. Назвіть процедуру ім'ям, яке має сенс, щоб отримати корисний засіб, за допомогою якого можна визначити, у чому проблема. При виникненні помилки ви побачите лінію відмови (залежно від контексту виконання).

Наприклад:

CALL AttemptedToInsertSomethingInvalid;

Зауважте, що під час створення процедури не проводиться перевірка таких дій. Тож, хоч у чомусь схожій на компільованій мові, ви ніколи не можете викликати функцію, якої не було, у такому сценарії він просто не працює під час виконання, що саме в цьому випадку бажано!


1
Це відчувається як найправильніша, ґрунтовна відповідь на мене, і було саме те, що я хотів. Як і в ОП, у мене є кілька тестів (перевірка введення), які мені потрібно запустити, і я не хотів їх вкладати, так що це добре працює для мене.
Fodagus

12

Щоб вирішити цю ситуацію портативно (тобто працюватиме на всіх базах даних, оскільки вона не використовує MySQL-мітку Kung fu), розбийте процедуру на логічні частини, наприклад:

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
Юкс, чому б замість цього не використати перше рішення?
Pacerier

1
Бажаю, щоб я міг проголосувати за це двічі. Просто тому, що SQL не є справжньою мовою програмування, нікому не дає приводу написати 200+ рядків коду за одну процедуру.
Макс Хайбер

Це відповідь просто неправильна чи я щось пропускаю? Чому він має надбавки? Очевидно, що є спосіб досягти цього, що демонструється прийнятим рішенням.
jlh

@jlh це було не так (текст виправлено зараз), оскільки я не знав про техніку мітки mysql, але код не помиляється - він буде працювати на будь-якій БД насправді.
богем

2

Чому б не це:

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
Код дуже довгий ... я не можу цим користуватися ... Це просто зразок.
Джо Іджам

Незалежно від довжини, він не виконається.
Стівен

Якщо ви турбуєтесь про відступ, просто скасуйте весь розділ у ifвиписці. Це логічно ідентично "ранньому поверненню".
bobobobo

@bobobobo, Він говорить, що в його випадку логічно набагато більше сенсу не намагатися переймати логіку навколо цього обмеження sql.
Pacerier

1
Можливо, у нього є логін з великою кількістю чеків "якщо x NULL THEN SETresult = -1". Ви хочете, щоб це дійсно перестало робити справи. Це зменшує складність ifs. Менше {} оприлюднено
борджаб

2

Це працює для мене:

 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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.