Mysql - Cách thoát / thoát khỏi thủ tục được lưu trữ


131

Tôi có câu hỏi rất đơn giản nhưng tôi không nhận được bất kỳ mã đơn giản nào để thoát khỏi SP bằng Mysql. Bất cứ ai có thể chia sẻ với tôi làm thế nào để làm điều đó?

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
Hoặc, bạn có thể sử dụng IF tablename IS NOT NULL THEN...;)
OMG Ponies

4
Tôi đang cố gắng cắt ngắn ... nếu không tôi phải viết mã bên trong câu lệnh IF và đây không phải là câu lệnh EXIT duy nhất ... rằng bạn cần chức năng thoát thay vì chúng tôi thực hiện nhiều IF trong Stored Proc.
Joe Ijam

URL tham chiếu tốt: byte.com/topic/mysql/answers/ từ
Avishek

Câu trả lời:


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
Tuyệt quá! Bạn thậm chí còn chỉ ra rằng END proc_label;cú pháp (được hiển thị trong hầu hết các ví dụ chính thức của MySQL) là không cần thiết. (đây là một cách tuyệt vời để nhận xét một Proc được lưu trữ mà không cần phải cuộn xuống phía dưới để đặt */vào vị trí)

2
bạn có thể để lại và trả lại một giá trị?
ygaradon

35
Chỉ cần gắn nhãn phần BEGIN của mỗi Proc 'this_proc'. Bởi vì LEAVE this_proc;âm thanh hoàn hảo!
SNag

@ygaradon Thủ tục lưu trữ không trả về giá trị. Bạn cần sử dụng một hàm được lưu trữ và return <value>trả về một giá trị.
David Harkness

1
Tôi nghĩ rằng không gian là cần thiết giữa :BEGINnhư proc_label:BEGINđã đưa ra lỗi cú pháp trong khi proc_label: BEGINlàm việc.
Umair Malhi

13

Nếu bạn muốn "thoát sớm" cho tình huống không có lỗi, thì hãy sử dụng câu trả lời được chấp nhận được đăng bởi @piotrm. Tuy nhiên, thông thường nhất, bạn sẽ được bảo lãnh do một điều kiện lỗi (đặc biệt là trong thủ tục SQL).

Kể từ MySQL v5.5, bạn có thể ném ngoại lệ. Xử lý ngoại lệ phủ nhận, vv sẽ đạt được kết quả tương tự, nhưng theo cách sạch sẽ hơn, sâu sắc hơn.

Đây là cách thực hiện:

DECLARE CUSTOM_EXCEPTION CONDITION FOR SQLSTATE '45000';

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

Lưu ý SQLSTATE '45000'tương đương với "Điều kiện ngoại lệ do người dùng xác định". Theo mặc định, điều này sẽ tạo ra một mã lỗi 1644(có cùng ý nghĩa). Lưu ý rằng bạn có thể ném các mã điều kiện hoặc mã lỗi khác nếu muốn (cộng với các chi tiết bổ sung để xử lý ngoại lệ).

Để biết thêm về chủ đề này, hãy xem:

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

Cách phát sinh lỗi trong hàm MySQL

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

Phụ lục

Khi tôi đọc lại bài đăng này của tôi, tôi nhận ra rằng tôi có thêm một cái gì đó để thêm. Trước MySQL v5.5, có một cách để giả lập ném ngoại lệ. Chính xác thì đây không phải là điều tương tự, nhưng đây là điều tương tự: Tạo lỗi thông qua việc gọi một thủ tục không tồn tại. Gọi thủ tục bằng một tên có ý nghĩa để có được một phương tiện hữu ích để xác định vấn đề là gì. Khi xảy ra lỗi, bạn sẽ thấy dòng lỗi (tùy thuộc vào bối cảnh thực hiện của bạn).

Ví dụ:

CALL AttemptedToInsertSomethingInvalid;

Lưu ý rằng khi bạn tạo một thủ tục, không có xác nhận được thực hiện trên những thứ đó. Vì vậy, trong khi ở một thứ như ngôn ngữ được biên dịch, bạn không bao giờ có thể gọi một hàm không có ở đó, trong một kịch bản như thế này, nó sẽ đơn giản thất bại trong thời gian chạy, đó chính xác là điều mong muốn trong trường hợp này!


1
Cảm giác này giống như câu trả lời chính xác, thấu đáo nhất đối với tôi và chính xác là những gì tôi muốn. Giống như OP, tôi có một số thử nghiệm (xác thực đầu vào) tôi cần chạy và tôi không muốn lồng tất cả chúng, vì vậy điều này hoạt động tốt với tôi.
Fodagus

12

Để xử lý tình huống này theo cách di động (nghĩa là sẽ hoạt động trên tất cả các cơ sở dữ liệu vì nó không sử dụng nhãn Kung fu của MySQL), hãy chia quy trình thành các phần logic, như sau:

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, tại sao không sử dụng giải pháp đầu tiên thay thế?
Pacerier

1
Ước gì tôi có thể bỏ phiếu này lên hai lần. Chỉ vì SQL không phải là ngôn ngữ lập trình thực sự không cung cấp cho bất kỳ ai một lý do để viết hơn 200 dòng mã trong một quy trình.
Max Heiber

Là câu trả lời này chỉ đơn giản là sai hoặc tôi đang thiếu một cái gì đó? Tại sao nó có upvote? Rõ ràng có một cách để đạt được điều này được thể hiện bằng giải pháp được chấp nhận.
jlh

@jlh nó sai (văn bản điều chỉnh bây giờ) trong đó tôi không biết về kỹ thuật nhãn mysql, nhưng mã này là không sai - nó sẽ làm việc, trên bất kỳ DB thực sự.
Bohemian

2

Tại sao không phải là điều này:

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
Mã này rất dài ... tôi không thể sử dụng cái này ... Đó chỉ là một mẫu.
Joe Ijam

Bất kể chiều dài, nó sẽ không thực hiện.
Stephen

Nếu bạn lo lắng về việc thụt lề, chỉ cần bỏ qua toàn bộ phần trong ifcâu lệnh. Nó giống hệt như một "sự trở lại sớm".
bobobobo

@bobobobo, anh ấy nói trong trường hợp của mình, điều đó hợp lý hơn nhiều so với việc không điều chỉnh lại logic xung quanh giới hạn sql này.
Pacerier

1
Có thể anh ta đã đăng nhập với rất nhiều kiểm tra "nếu x IS NULL THEN SETresult = -1". Bạn muốn nó thực sự ngừng làm việc. Nó làm giảm sự phức tạp của ifs. Ít hơn {} annidated
borjab

2

Điều này làm việc cho tôi:

 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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.