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%TYPEis
    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 varchar100))
    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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM