Mysql - Cara keluar / keluar dari prosedur tersimpan


131

Saya punya pertanyaan yang sangat sederhana tetapi saya tidak mendapatkan kode sederhana untuk keluar dari SP menggunakan Mysql. Adakah yang bisa berbagi dengan saya cara melakukannya?

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
Atau, Anda bisa menggunakan IF tablename IS NOT NULL THEN...;)
OMG Ponies

4
Saya mencoba untuk memotong pendek ... kalau tidak saya harus kode di dalam pernyataan IF, dan ini bukan satu-satunya pernyataan EXIT ... bahwa yi memerlukan fungsi keluar, bukan kita melakukan beberapa IF di dalam Stored Proc.
Joe Ijam

URL referensi yang bagus: bytes.com/topic/mysql/answers/…
Avishek

Jawaban:


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
Bagus! Anda bahkan menunjukkan bahwa END proc_label;sintaks (ditunjukkan dalam sebagian besar contoh MySQL resmi) tidak diperlukan. (ini adalah cara yang bagus untuk berkomentar tentang proc yang disimpan tanpa harus menggulir ke bawah untuk menempatkannya */)

2
dapatkah kamu pergi dan mengembalikan nilainya?
ygaradon

35
Cukup beri label bagian BEGIN dari setiap proc 'this_proc'. Karena LEAVE this_proc;kedengarannya sempurna!
SNag

@ygaradon Prosedur tersimpan tidak mengembalikan nilai. Anda harus menggunakan fungsi tersimpan dan return <value>mengembalikan nilai.
David Harkness

1
Saya pikir ruang diperlukan antara :dan BEGINkarena proc_label:BEGINmemberikan kesalahan sintaks saat proc_label: BEGINbekerja.
Umair Malhi

13

Jika Anda ingin "keluar awal" untuk situasi di mana tidak ada kesalahan, maka gunakan jawaban yang diterima yang diposting oleh @piotrm. Paling biasanya, Anda akan menyerah karena kondisi kesalahan (terutama dalam prosedur SQL).

Pada MySQL v5.5 Anda bisa melempar pengecualian. Meniadakan penangan pengecualian, dll. Yang akan mencapai hasil yang sama, tetapi dengan cara yang lebih bersih dan lebih pedih.

Begini caranya:

DECLARE CUSTOM_EXCEPTION CONDITION FOR SQLSTATE '45000';

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

Catatan SQLSTATE '45000'sama dengan "Kondisi pengecualian yang ditentukan pengguna yang tidak ditangani". Secara default, ini akan menghasilkan kode kesalahan 1644(yang memiliki arti yang sama). Perhatikan bahwa Anda dapat membuang kode kondisi lain atau kode kesalahan jika Anda mau (ditambah detail tambahan untuk penanganan pengecualian).

Untuk lebih lanjut tentang hal ini, lihat:

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

Cara meningkatkan kesalahan dalam fungsi MySQL

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

Tambahan

Ketika saya membaca kembali posting saya ini, saya menyadari bahwa saya memiliki sesuatu yang ditambahkan. Sebelum ke MySQL v5.5, ada cara untuk meniru melempar pengecualian. Ini bukan hal yang persis sama, tetapi ini analog: Buat kesalahan melalui memanggil prosedur yang tidak ada. Panggil prosedur dengan nama yang bermakna untuk mendapatkan cara yang berguna untuk menentukan apa masalahnya. Ketika kesalahan terjadi, Anda akan melihat garis kegagalan (tergantung pada konteks eksekusi Anda).

Sebagai contoh:

CALL AttemptedToInsertSomethingInvalid;

Perhatikan bahwa ketika Anda membuat prosedur, tidak ada validasi yang dilakukan pada hal-hal tersebut. Jadi sementara dalam sesuatu seperti bahasa yang dikompilasi, Anda tidak akan pernah bisa memanggil fungsi yang tidak ada di sana, dalam skrip seperti ini, ia hanya akan gagal saat runtime, yang persis seperti yang diinginkan dalam kasus ini!


1
Ini terasa seperti jawaban yang paling benar, menyeluruh bagi saya dan persis seperti yang saya inginkan. Seperti OP, saya punya beberapa tes (input validasi) yang perlu saya jalankan dan saya tidak ingin membuat semuanya, jadi ini berfungsi dengan baik untuk saya.
Fodagus

12

Untuk menangani situasi ini dengan cara yang portabel (yaitu akan bekerja pada semua database karena tidak menggunakan label MySQL Kung fu), pisahkan prosedur menjadi beberapa bagian logika, seperti ini:

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, mengapa tidak menggunakan solusi pertama?
Pacerier

1
Seandainya saya bisa memilih ini dua kali. Hanya karena SQL bukan bahasa pemrograman nyata tidak memberikan alasan bagi siapa pun untuk menulis 200+ baris kode dalam satu prosedur.
Max Heiber

Apakah jawaban ini benar-benar salah atau saya melewatkan sesuatu? Mengapa ada upvotes? Jelas ada cara untuk mencapai ini yang ditunjukkan oleh solusi yang diterima.
jlh

@jlh itu adalah salah (teks dikoreksi sekarang) bahwa saya tidak tahu tentang teknik label mysql, tetapi kode ini tidak salah - itu akan bekerja, pada setiap DB sebenarnya.
Bohemian

2

Kenapa tidak ini:

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
Kode ini sangat panjang ... saya tidak bisa menggunakan ini ... Itu hanya contoh.
Joe Ijam

Tidak peduli panjangnya, itu tidak akan dieksekusi.
Stephen

Jika Anda khawatir tentang indentasi, lepaskan seluruh bagian dalam ifpernyataan. Secara logis identik dengan "pengembalian awal".
bobobobo

@bobobobo, Dia mengatakan dalam kasus itu membuat logis jauh lebih merasakan tidak tot rewire logika sekitar keterbatasan sql ini.
Pacerier

1
Mungkin dia memiliki login dengan banyak cek "jika x IS NULL THEN SETESult = -1". Anda ingin benar-benar berhenti melakukan sesuatu. Ini mengurangi kompleksitas ifs. Dikurangi {} dibatalkan
borjab

2

Ini bekerja untuk saya:

 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;
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.