1. 程式人生 > >MySQL儲存過程中的3種迴圈,儲存過程的基本語法,ORACLE與MYSQL的儲存過程/函式的使用區別,退出儲存過程方法

MySQL儲存過程中的3種迴圈,儲存過程的基本語法,ORACLE與MYSQL的儲存過程/函式的使用區別,退出儲存過程方法

 

學無止境

部落格園   首頁   新隨筆   聯絡   訂閱訂閱  管理

隨筆-1968  評論-103  文章-4 

MySQL儲存過程中的3種迴圈,儲存過程的基本語法,ORACLE與MYSQL的儲存過程/函式的使用區別,退出儲存過程方法

 

在MySQL儲存過程的語句中有三個標準的迴圈方式:WHILE迴圈,LOOP迴圈以及REPEAT迴圈。還有一種非標準的迴圈方式:GOTO,不過這種迴圈方式最好別用,很容易引起程式的混亂,在這裡就不錯具體介紹了。

這幾個迴圈語句的格式如下:

  • WHILE……DO……END WHILE
  • REPEAT……UNTIL END REPEAT
  • LOOP……END LOOP
  • GOTO

    下面首先使用第一種迴圈編寫一個例子。

複製程式碼

mysql> create procedure pro10()
    -> begin
    -> declare i int;
    -> set i=0;
    -> while i<5 do
    ->     insert into t1(filed) values(i);
    ->     set i=i+1;
    -> end while;
    -> end;//

複製程式碼

Query OK, 0 rows affected (0.00 sec)
    在這個例子中,INSERT和SET語句在WHILE和END WHILE之間,當變數i大於等於5的時候就退出迴圈。使用set i=0;語句是為了防止一個常見的錯誤,如果沒有初始化,i預設變數值為NULL,而NULL和任何值操作的結果都是NULL。
    執行一下這個儲存過程併產看一下執行結果:
mysql> delete from t1//
Query OK, 0 rows affected (0.00 sec)
mysql> call pro10()//
Query OK, 1 row affected (0.00 sec)
mysql> select * from t1//
+——-+
| filed |
+——-+
|     0 |
|     1 |
|     2 |
|     3 |
|     4 |
+——-+
5 rows in set (0.00 sec)
    以上就是執行結果,有5行資料插入到資料庫中,證明儲存過程編寫正確無誤^_^。

    再來看一下第二個迴圈控制指令 REPEAT……END REPEAT。使用REPEAT迴圈控制語句編寫下面這個儲存過程:

複製程式碼

mysql> create procedure pro11()
    -> begin
    -> declare i int default 0;
    -> repeat
    ->     insert into t1(filed) values(i);
    ->     set i=i+1;
    ->     until i>=5
    -> end repeat;
    -> end;//

複製程式碼

Query OK, 0 rows affected (0.00 sec)
    這個REPEAT迴圈的功能和前面WHILE迴圈一樣,區別在於它的執行後檢查是否滿足迴圈條件(until i>=5),而WHILE則是執行前檢查(while i<5 do)。
    不過要注意until i>=5後面不要加分號,如果加分號,就是提示語法錯誤。
    編寫完成後,呼叫一下這個儲存過程,並檢視結果:
mysql> delete from t1//
Query OK, 5 rows affected (0.00 sec)

mysql> call pro11()//
Query OK, 1 row affected (0.00 sec) #雖然在這裡顯示只有一行資料受到影響,但是下面選擇資料的話,還是插入了5行資料。

mysql> select * from t1//
+——-+
| filed |
+——-+
|     0 |
|     1 |
|     2 |
|     3 |
|     4 |
+——-+
5 rows in set (0.00 sec)
一行就是執行結果,實際的作用和使用while編寫的儲存過程一樣,都是插入5行資料。

再來看一下第三個迴圈控制語句LOOP……END LOOP。編寫一個儲存過程程式如下:

複製程式碼

mysql> create procedure pro12()
    -> begin
    -> declare i int default 0;
    -> loop_label: loop
    ->     insert into t1(filed) values(i);
    ->     set i=i+1;
    ->     if i>=5 then
    ->         leave loop_label;
    ->     end if;
    -> end loop;
    -> end;//

複製程式碼

Query OK, 0 rows affected (0.00 sec)
從上面這個例子可以看出,使用LOOP編寫同樣的迴圈控制語句要比使用while和repeat編寫的要複雜一些:在迴圈內部加入了IF……END IF語句,在IF語句中又加入了LEAVE語句,LEAVE語句的意思是離開迴圈,LEAVE的格式是:LEAVE 迴圈標號。
    編寫完儲存過程程式後,來執行並檢視一下執行結果:
mysql> delete from t1//
Query OK, 5 rows affected (0.00 sec)

 

mysql> call pro12//
Query OK, 1 row affected (0.00 sec) #雖然說只有一行資料受影響,但是實際上是插入了5行資料。

mysql> select * from t1//
+——-+
| filed |
+——-+
|     0 |
|     1 |
|     2 |
|     3 |
|     4 |
+——-+
5 rows in set (0.00 sec)
    執行結果和使用WHILE、LOOP編寫的迴圈一樣,都是往標中插入5行值。

   Labels   標號和 END Labels 結束標號
   在使用loop的時候,使用到的labels標號,對於labels可以用到while,loop,rrepeat等迴圈控制語句中。而且有必要好好認識一下lables!!
mysql> create procedure pro13()
    -> label_1:begin
    -> label_2:while 0=1 do leave label_2;end while;
    -> label_3:repeat leave label_3;until 0=0 end repeat;
    -> label_4:loop leave label_4;end loop;
    -> end;//
Query OK, 0 rows affected (0.00 sec)
    上面這裡例子顯示了可以在BEGIN、WHILE、REPEAT或者LOOP語句前使用語句標號,語句標號只能在合法的語句前使用,所以LEAVE label_3意味著離開語句標號名為label_3的語句或符合語句。
    其實,也可以使用END labels來表示標號結束符。
mysql> create procedure pro14()
    -> label_1:begin
    -> label_2:while 0=1 do leave label_2;end while label_2;
    -> label_3:repeat leave label_3;until 0=0 end repeat label_3;
    -> label_4:loop leave label_4;end loop label_4;
    -> end label_1;//
Query OK, 0 rows affected (0.00 sec)
    上面就是使用了標號結束符,其實這個結束標號並不是十分有用,而且他必須和開始定義的標號名字一樣,否則就會報錯。如果要養成一個良好的程式設計習慣方便他人閱讀的話,可以使用這個標號結束符。

ITERATE 迭代        
     如果是在ITERATE語句,即迭代語句中的話,就必須使用LEAVE語句。ITERATE只能出現在LOOP,REPEAT和WHILE語句中,它的意思是“再次迴圈”,例如:
mysql> create procedure pro15()

 


    -> begin
    -> declare i int default 0;
    -> loop_label:loop
    ->     if i=3 then
    ->         set i=i+1;
    ->         iterate loop_label;
    ->     end if;
    ->     insert into t1(filed) values(i);
    ->     set i=i+1;
    ->     if i>=5 then
    ->        leave loop_label;
    ->     end if;
    ->   end loop;
    -> end;//
Query OK, 0 rows affected (0.00 sec)
    iterate語句和leave語句一樣,也是在迴圈內部使用,它有點類似於C/C++語言中的continue。
    那麼這個儲存程式是怎麼執行的的?首先i的值為0,條件判斷語句if i=3 then判斷為假,跳過if語段,向資料庫中插入0,然後i+1,同樣後面的if i>=5 then判斷也為假,也跳過;繼續迴圈,同樣插入1和2;在i=3的時候條件判斷語句if i=3 then判斷為真,執行i=i+1,i值為4,然後執行迭代iterate loop_label;,即語句執行到iterate loop_label;後直接跳到if i=3 then判斷語句,執行判斷,這個時候由於i=4,if i=3 then判斷為假,跳過IF語段,將4新增到表中,i變為5,條件判斷if i>=5 then判斷為真,執行leave loop_label;跳出loop迴圈,然後執行end;//,結束整個儲存過程。
    綜上所述,資料庫中將插入數值:0,1,2,4。執行儲存過程,並檢視結果:|
mysql> delete from t1//
Query OK, 5 rows affected (0.00 sec)

 

mysql> call pro15//
Query OK, 1 row affected (0.00 sec)

mysql> select * from t1//
+——-+
| filed |
+——-+
|     0 |
|     1 |
|     2 |
|     4 |
+——-+
4 rows in set (0.00 sec)

和我們上面分析的結果一樣,只插入了數值0,1,2,4。

 

儲存過程如同一門程式設計語言,同樣包含了資料型別、流程控制、輸入和輸出和它自己的函式庫。


--------------------基本語法--------------------

一.建立儲存過程
create procedure sp_name()
begin
.........
end

二.呼叫儲存過程
1.基本語法:call sp_name()
注意:儲存過程名稱後面必須加括號,哪怕該儲存過程沒有引數傳遞

三.刪除儲存過程
1.基本語法:
drop procedure sp_name//

2.注意事項
(1)不能在一個儲存過程中刪除另一個儲存過程,只能呼叫另一個儲存過程

四.其他常用命令

1.show procedure status
顯示資料庫中所有儲存的儲存過程基本資訊,包括所屬資料庫,儲存過程名稱,建立時間等

2.show create procedure sp_name
顯示某一個MySQL儲存過程的詳細資訊


--------------------資料型別及運算子--------------------
一、基本資料型別:

二、變數:

自定義變數:DECLARE   a INT ; SET a=100;    可用以下語句代替:DECLARE a INT DEFAULT 100;

變數分為使用者變數系統變數,系統變數又分為會話和全域性級變數

使用者變數:使用者變數名一般以@開頭,濫用使用者變數會導致程式難以理解及管理

1、 在mysql客戶端使用使用者變數
mysql> SELECT 'Hello World' into @x;
mysql> SELECT @x;

mysql> SET @y='Goodbye Cruel World';
mysql> select @y;

mysql> SET @z=1+2+3;
mysql> select @z;


2、 在儲存過程中使用使用者變數

mysql> CREATE PROCEDURE GreetWorld( ) SELECT CONCAT(@greeting,' World');
mysql> SET @greeting='Hello';
mysql> CALL GreetWorld( );


3、 在儲存過程間傳遞全域性範圍的使用者變數
mysql> CREATE PROCEDURE p1( )   SET @last_procedure='p1';
mysql> CREATE PROCEDURE p2( ) SELECT CONCAT('Last procedure was ',@last_procedure);
mysql> CALL p1( );
mysql> CALL p2( );

 

三、運算子:
1.算術運算子
+     加   SET var1=2+2;       4
-     減   SET var2=3-2;       1
*      乘   SET var3=3*2;       6
/     除   SET var4=10/3;      3.3333
DIV   整除 SET var5=10 DIV 3; 3
%     取模 SET var6=10%3 ;     1

2.比較運算子
>            大於 1>2 False
<            小於 2<1 False
<=           小於等於 2<=2 True
>=           大於等於 3>=2 True
BETWEEN      在兩值之間 5 BETWEEN 1 AND 10 True
NOT BETWEEN 不在兩值之間 5 NOT BETWEEN 1 AND 10 False
IN           在集合中 5 IN (1,2,3,4) False
NOT IN       不在集合中 5 NOT IN (1,2,3,4) True
=             等於 2=3 False
<>, !=       不等於 2<>3 False
<=>          嚴格比較兩個NULL值是否相等 NULL<=>NULL True
LIKE          簡單模式匹配 "Guy Harrison" LIKE "Guy%" True
REGEXP       正則式匹配 "Guy Harrison" REGEXP "[Gg]reg" False
IS NULL      為空 0 IS NULL False
IS NOT NULL 不為空 0 IS NOT NULL True

3.邏輯運算子

4.位運算子
|   或
&   與
<< 左移位
>> 右移位
~   非(單目運算,按位取反)

註釋:

mysql儲存過程可使用兩種風格的註釋
雙橫槓:--

該風格一般用於單行註釋
c風格:/* 註釋內容 */ 一般用於多行註釋

--------------------流程控制--------------------
一、順序結構
二、分支結構

if
case

三、迴圈結構
for迴圈
while迴圈
loop迴圈
repeat until迴圈

注:
區塊定義,常用
begin
......
end;
也可以給區塊起別名,如:
lable:begin
...........
end lable;
可以用leave lable;跳出區塊,執行區塊以後的程式碼。

可以提前退出儲存過程(函式直接return)。

begin和end如同C語言中的{ 和 }。

--------------------輸入和輸出--------------------

mysql儲存過程的引數用在儲存過程的定義,共有三種引數型別,IN,OUT,INOUT
Create procedure|function([[IN |OUT |INOUT ] 引數名 資料類形...])

IN 輸入引數
表示該引數的值必須在呼叫儲存過程時指定,在儲存過程中修改該引數的值不能被返回,為預設值

OUT 輸出引數
該值可在儲存過程內部被改變,並可返回

INOUT 輸入輸出引數
呼叫時指定,並且可被改變和返回

IN引數例子:
CREATE PROCEDURE sp_demo_in_parameter(IN p_in INT)
BEGIN
SELECT p_in; --查詢輸入引數
SET p_in=2; --修改
select p_in;--檢視修改後的值
END;

執行結果:
mysql> set @p_in=1
mysql> call sp_demo_in_parameter(@p_in)

mysql> select @p_in;

以上可以看出,p_in雖然在儲存過程中被修改,但並不影響@p_id的值

OUT引數例子
建立:
mysql> CREATE PROCEDURE sp_demo_out_parameter(OUT p_out INT)
BEGIN
SELECT p_out;/*檢視輸出引數*/
SET p_out=2;/*修改引數值*/
SELECT p_out;/*看看有否變化*/
END;

執行結果:
mysql> SET @p_out=1
mysql> CALL sp_demo_out_parameter(@p_out)

mysql> SELECT @p_out;

INOUT引數例子:
mysql> CREATE PROCEDURE sp_demo_inout_parameter(INOUT p_inout INT)
BEGIN
SELECT p_inout;
SET p_inout=2;
SELECT p_inout;
END;

執行結果:
set @p_inout=1
call sp_demo_inout_parameter(@p_inout) //

select @p_inout;

 

 

附:函式庫
mysql儲存過程基本函式包括:字串型別,數值型別,日期型別

一、字串類
CHARSET(str) //返回字串字符集
CONCAT (string2 [,… ]) //連線字串
INSTR (string ,substring ) //返回substring首次在string中出現的位置,不存在返回0
LCASE (string2 ) //轉換成小寫
LEFT (string2 ,length ) //從string2中的左邊起取length個字元
LENGTH (string ) //string長度
LOAD_FILE (file_name ) //從檔案讀取內容
LOCATE (substring , string [,start_position ] ) 同INSTR,但可指定開始位置
LPAD (string2 ,length ,pad ) //重複用pad加在string開頭,直到字串長度為length
LTRIM (string2 ) //去除前端空格
REPEAT (string2 ,count ) //重複count次
REPLACE (str ,search_str ,replace_str ) //在str中用replace_str替換search_str
RPAD (string2 ,length ,pad) //在str後用pad補充,直到長度為length
RTRIM (string2 ) //去除後端空格
STRCMP (string1 ,string2 ) //逐字元比較兩字串大小,
SUBSTRING (str , position [,length ]) //從str的position開始,取length個字元,
注:mysql中處理字串時,預設第一個字元下標為1,即引數position必須大於等於1
mysql> select substring(’abcd’,0,2);
+———————–+
| substring(’abcd’,0,2) |
+———————–+
|                       |
+———————–+
1 row in set (0.00 sec)

mysql> select substring(’abcd’,1,2);
+———————–+
| substring(’abcd’,1,2) |
+———————–+
| ab                    |
+———————–+
1 row in set (0.02 sec)

TRIM([[BOTH|LEADING|TRAILING] [padding] FROM]string2) //去除指定位置的指定字元
UCASE (string2 ) //轉換成大寫
RIGHT(string2,length) //取string2最後length個字元
SPACE(count) //生成count個空格

二、數值型別

ABS (number2 ) //絕對值
BIN (decimal_number ) //十進位制轉二進位制
CEILING (number2 ) //向上取整
CONV(number2,from_base,to_base) //進位制轉換
FLOOR (number2 ) //向下取整
FORMAT (number,decimal_places ) //保留小數位數
HEX (DecimalNumber ) //轉十六進位制
注:HEX()中可傳入字串,則返回其ASC-11碼,如HEX(’DEF’)返回4142143
也可以傳入十進位制整數,返回其十六進位制編碼,如HEX(25)返回19
LEAST (number , number2 [,..]) //求最小值
MOD (numerator ,denominator ) //求餘
POWER (number ,power ) //求指數
RAND([seed]) //隨機數
ROUND (number [,decimals ]) //四捨五入,decimals為小數位數]

注:返回型別並非均為整數,如:

(1)預設變為整形值
mysql> select round(1.23);
+————-+
| round(1.23) |
+————-+
|           1 |
+————-+
1 row in set (0.00 sec)

mysql> select round(1.56);
+————-+
| round(1.56) |
+————-+
|           2 |
+————-+
1 row in set (0.00 sec)

(2)可以設定小數位數,返回浮點型資料

mysql> select round(1.567,2);
+—————-+
| round(1.567,2) |
+—————-+
|           1.57 |
+—————-+
1 row in set (0.00 sec)

SIGN (number2 ) //返回符號,正負或0
SQRT(number2) //開平方

三、日期型別

ADDTIME (date2 ,time_interval ) //將time_interval加到date2
CONVERT_TZ (datetime2 ,fromTZ ,toTZ ) //轉換時區
CURRENT_DATE ( ) //當前日期
CURRENT_TIME ( ) //當前時間
CURRENT_TIMESTAMP ( ) //當前時間戳
DATE (datetime ) //返回datetime的日期部分
DATE_ADD (date2 , INTERVAL d_value d_type ) //在date2中加上日期或時間
DATE_FORMAT (datetime ,FormatCodes ) //使用formatcodes格式顯示datetime
DATE_SUB (date2 , INTERVAL d_value d_type ) //在date2上減去一個時間
DATEDIFF (date1 ,date2 ) //兩個日期差
DAY (date ) //返回日期的天
DAYNAME (date ) //英文星期
DAYOFWEEK (date ) //星期(1-7) ,1為星期天
DAYOFYEAR (date ) //一年中的第幾天
EXTRACT (interval_name FROM date ) //從date中提取日期的指定部分
MAKEDATE (year ,day ) //給出年及年中的第幾天,生成日期串
MAKETIME (hour ,minute ,second ) //生成時間串
MONTHNAME (date ) //英文月份名
NOW ( ) //當前時間
SEC_TO_TIME (seconds ) //秒數轉成時間
STR_TO_DATE (string ,format ) //字串轉成時間,以format格式顯示
TIMEDIFF (datetime1 ,datetime2 ) //兩個時間差
TIME_TO_SEC (time ) //時間轉秒數]
WEEK (date_time [,start_of_week ]) //第幾周
YEAR (datetime ) //年份
DAYOFMONTH(datetime) //月的第幾天
HOUR(datetime) //小時
LAST_DAY(date) //date的月的最後日期
MICROSECOND(datetime) //微秒
MONTH(datetime) //月
MINUTE(datetime) //分

注:可用在INTERVAL中的型別:DAY ,DAY_HOUR ,DAY_MINUTE ,DAY_SECOND ,HOUR ,HOUR_MINUTE ,HOUR_SECOND ,MINUTE ,MINUTE_SECOND,MONTH ,SECOND ,YEAR
DECLARE variable_name [,variable_name...] datatype [DEFAULT value]; 
其中,datatype為mysql的資料型別,如:INT, FLOAT, DATE, VARCHAR(length)

例:

DECLARE l_int INT unsigned default 4000000; 
DECLARE l_numeric NUMERIC(8,2) DEFAULT 9.95; 
DECLARE l_date DATE DEFAULT '1999-12-31'; 
DECLARE l_datetime DATETIME DEFAULT '1999-12-31 23:59:59';
DECLARE l_varchar VARCHAR(255) DEFAULT 'This will not be padded';

 ORACLE與MYSQL的儲存過程/函式的使用區別

  • 編號 類別 ORACLE MYSQL 註釋
    1 建立儲存過程語句不同 create or replace procedure P_ADD_FAC(
       id_fac_cd  IN ES_FAC_UNIT.FAC_CD%TYPE) is
    DROP PROCEDURE IF EXISTS `SD_USER_P_ADD_USR`;
    create procedure P_ADD_FAC(
           id_fac_cd  varchar(100))

    1.在建立儲存過程時如果存在同名的儲存過程,會刪除老的儲存過程. 
      oracle使用create or replace.
      mysql使用先刪除老的儲存過程,然後再建立新的儲存過程.
    2. oracle 儲存過程可以定義在package中,也可以定義在Procedures中. 如果定義在包中,一個包中可以包含多個儲存過程和方法.如果定義在Procedures中,儲存過程中不可以定義多個儲存過程. 
       Mysql  儲存過程中不可以定義多個儲存過程. 
    3. oracle中字串型別可以使用varchar2.  
       Mysql 需要使用varchar
    4. Oracle中引數varchar長度不是必須的,
       Mysql中引數varchar長度是必須的, 比如varchar(100) 
    2 建立函式語句不同 CREATE OR REPLACEFUNCTION F_ROLE_FACS_GRP(
         ii_role_int_key IN SD_ROLE.ROLE_INT_KEY%TYPE
        ) RETURN VARCHAR2
    DROP FUNCTION IF EXISTS `SD_ROLE_F_ROLE_FACS_GRP`;
    CREATE  FUNCTION `SD_ROLE_F_ROLE_FACS_GRP`(
     ii_role_int_key INTEGER(10)
    ) RETURNS varchar(1000) 
    1.在建立函式時如果存在同名的函式,會刪除老的函式.  
      oracle使用create or replace.
      mysql使用先刪除老的函式,然後再建立新的函式.
    2. oracle 函式可以定義在package中,也可以定義在Functions中. 如果定義在包中,一個包中可以包含多個儲存過程和函式.如果定義在Functions中,每個函式只能定義一個函式.
       Mysql  Functions不可以定義多個函式. 
    3.  oracle返回值用return. 
        Mysql返回值用returns. 
    3 傳入引數寫法不同 procedure P_ADD_FAC(
       id_fac_cd  IN ES_FAC_UNIT.FAC_CD%TYPE)
    create procedure P_ADD_FAC(
         (in) id_fac_cd  varchar(100))

    1. oracle儲存過程引數可以定義為表的欄位型別.
       Mysql儲存過程不支援這種定義方法.需要定義變數的實際型別和長度.
    2. oracle 引數型別in/out/inout寫在引數名後面. 
       Mysql  引數型別in/out/inout寫在引數名前面.
    3. oracle 引數型別in/out/inout 都必須寫.
       Mysql  引數型別如果是in,則可以省略. 如果是out或inout則不能省略.
    注意: mysql中指定引數為IN, OUT, 或INOUT 只對PROCEDURE是合法的。(FUNCTION引數總是被認為是IN引數) RETURNS字句只能對FUNCTION做指定,對函式而言這是強制的。它用來指定函式的返回型別,而且函式體必須包含一個RETURN value語句。  
     
    function func_name(
               gw_id  in(out)  varchar2 )
    create function func_name(
           gw_id varchar(100))
    4 包的宣告方式 create or replace package/package body package name 拆分成多個儲存過程或函式 oracle可以建立包,包中可以包含多個儲存過程和方法. 
    mysql沒有沒有包這個概念,可以分別建立儲存過程和方法. 每個儲存過程或方法都需要放在一個檔案中. 
    例1: 方法命名 
    oracle 中SD_FACILITY_PKG.F_SEARCH_FAC 
    to mysql SD_FACILITY_F_SEARCH_FAC 
    例2: 過程命名
    oracle 中SD_FACILITY_PKG.P_ADD_FAC
    to mysql SD_FACILITY_P_ADD_FAC 
    5 儲存過程返回語句不一樣 return; LEAVE proc; (proc 代表最外層的begin end) oracle儲存過程和方法都可以使用return退出當前過程和方法. 
    Mysql儲存過程中只能使用leave退出當前儲存過程.不可以使用return. 
    Mysql方法可以使用return退出當前方法. 
    6 儲存過程異常處理不一樣 EXCEPTION
        WHEN OTHERS THEN
        ROLLBACK ;
        ov_rtn_msg := c_sp_name||'('|| li_debug_pos ||'):'||
            TO_CHAR(SQLCODE)||': '||SUBSTR(SQLERRM,1,100);
    DECLARE EXIT HANDLER FOR  SQLEXCEPTION 
     BEGIN
        ROLLBACK ;
        set ov_rtn_msg = concat(c_sp_name,'(', li_debug_pos ,'):',
            TO_CHAR(SQLCODE),': ',SUBSTR(SQLERRM,1,100));
     END;
    oracle : 內部異常不需要定義,在儲存過程或函式末尾寫上EXCEPTION後,後面的部分即為異常處理的部分.  oracle可以定義自定義異常,自定義異常需要使用raise關鍵字丟擲異常後,才可以在EXCEPTION中捕獲.

    mysql: mysql內部異常也需要先定義,在定義的同時也需要實現異常的功能. 
              目前mysql不支援自定義異常. 
    7 過程和函式的宣告變數的位置不同 宣告變數在begin…end體之前 宣告變數在begin...end體內,begin之後其他任何內容之前  
    8 NO_DATA_FOUND異常處理  EXCEPTION
            WHEN NO_DATA_FOUND THEN
                oi_rtn_cd := 1;
                ov_rtn_msg := SD_COMMON.P_GET_MSG('DP-CBM-01100a-016',
                                                     li_sub_rtn_cd,
                                                     lv_sub_rtn_msg
                                                     );
    使用FOUND_ROWS()代替NO_DATA_FOUND. 詳見註釋. oracle中: 
    NO_DATA_FOUND是遊標的一個屬性. 
    當select沒有查到資料就會出現 no data found 的異常,程式不會向下執行.

    Mysql: 
    沒有NO_DATA_FOUND這個屬性.但可是使用FOUND_ROWS()方法得到select語句查詢出來的資料.如果FOUND_ROWS()得到的值為0,就進入異常處理邏輯. 
    9 在儲存過程中呼叫儲存過程方式的不同 Procedure_Name(引數); Call Procedure_Name(引數); MYSQL儲存過程呼叫儲存過程,需要使用Call pro_name(引數).  
    Oracle呼叫儲存過程直接寫儲存過程名就可以了. 
    10 拋異常的方式不同 RAISE Exception_Name; 見備註 詳見<<2009002-OTMPPS-Difficult Questions-0001.doc>>中2.5 Mysql異常處理部分

     

  • 異常處理

  • MySQL的GET DIAGNOSTICS語句

    這是一個把我困擾已久的問題,今天偶然間解決了。

    以前用Oracle時經常會用到的三個東西:sql%rowcount、SQLCODE、SQLERRM
    sql%rowcount用於記錄最近一條DML語句修改的記錄條數,就如你在sqlplus下執行delete from之後提示已刪除xx行一樣。
    SQLCODE和SQLERRM是Oracle的異常處理函式,常被用於得到完整錯誤提示資訊,方便錯誤時處理。

    那麼問題來了,MySQL有沒有相似的功能呢?以前查了很久也沒有找到好的解決辦法,然而在5.6.4以後,MySQL提供了GET DIAGNOSTICS語法,那麼我的問題也隨之迎刃而解。

    簡單講GET DIAGNOSTICS能提供以下兩種資訊:
    語句資訊,例如錯誤資訊號或者語句影響的行數。
    錯誤資訊,例如錯誤號和錯誤訊息。
     

    如果一條語句產生了三種錯誤,診斷區域包含的語句和錯誤資訊類似這樣:

     

    Statement information: row count ... other statement information items ... Condition area list: Condition area 1: error code for condition 1 error message for condition 1 ... other condition information items ... Condition area 2: error code for condition 2: error message for condition 2 ... other condition information items ... Condition area 3: error code for condition 3 error message for condition 3 ... other condition information items ...

    使用GET DIAGNOSTICS需要注意的是,它或者包含語句資訊,或者包含錯誤資訊,但一個GET DIAGNOSTICS不會同時包含語句資訊和錯誤資訊,所以需要用兩個GET DIAGNOSTICS來獲得語句資訊和錯誤資訊。

    獲得語句資訊:
    GET DIAGNOSTICS @p1 = NUMBER, @p2 = ROW_COUNT;

    獲得錯誤資訊:
    GET DIAGNOSTICS CONDITION 1 @p3 = RETURNED_SQLSTATE, @p4 = MESSAGE_TEXT;

    語句資訊條目名稱有:
    NUMBER 
    | ROW_COUNT

    錯誤資訊條目名稱有:
    CLASS_ORIGIN 
    | SUBCLASS_ORIGIN
    | RETURNED_SQLSTATE
    | MESSAGE_TEXT
    | MYSQL_ERRNO
    | CONSTRAINT_CATALOG
    | CONSTRAINT_SCHEMA
    | CONSTRAINT_NAME
    | CATALOG_NAME
    | SCHEMA_NAME
    | TABLE_NAME
    | COLUMN_NAME
    | CURSOR_NAME

    為了確保獲得正確的主錯誤資訊,必須使用類似如下的語句:
    GET DIAGNOSTICS @cno = NUMBER;
    GET DIAGNOSTICS CONDITION @cno @errno = MYSQL_ERRNO;

    最後來看一個使用GET DIAGNOSTICS完整例子(摘自官方文件)
  • 複製程式碼

    BEGIN 
    -- Declare variables to hold diagnostics area information 
    DECLARE code CHAR(5) DEFAULT '00000'; 
    DECLARE msg TEXT; 
    DECLARE rows INT; 
    DECLARE result TEXT; 
    
    -- Declare exception handler for failed insert 
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION 
    BEGIN 
    GET DIAGNOSTICS CONDITION 1 code = RETURNED_SQLSTATE, msg = MESSAGE_TEXT; 
    END; 
    -- Perform the insert 
    INSERT INTO t1 (int_col) VALUES(value); 
    
    -- Check whether the insert was successful 
    IF code = '00000' THEN 
    GET DIAGNOSTICS rows = ROW_COUNT; 
    SET result = CONCAT('insert succeeded, row count = ',rows); 
    ELSE 
    SET result = CONCAT('insert failed, error = ',code,', message = ',msg); 
    END IF; 
    -- Say what happened 
    SELECT result; 
    END

    複製程式碼

    結果:insert failed, error = 42S02, message = Table 'ud_omcs.t1' doesn't exist

分類: mysql,mysql儲存過程函式事件

標籤: mysqlmysql儲存過程函式事件

好文要頂 關注我 收藏該文  

duanxz
關注 - 18
粉絲 - 661

+加關注

1

0

« 上一篇:mysql事務之二:MySQL隔離級別演示
» 下一篇:mysql分割槽表之二:MySQL的表的四種分割槽型別介紹

https://www.cnblogs.com/duanxz/p/3936618.html