mysql存儲過程詳細教程

轉載自->

記錄MYSQL存儲過程中的關鍵語法:
DELIMITER //
聲明語句結束符,用于區分;
CREATE PROCEDURE demo_in_parameter(IN p_in int)
聲明存儲過程
BEGIN .... END
存儲過程開始和結束符號
SET @p_in=1
變量賦值
DECLARE l_int int unsigned default 4000000;

變量定義
什么是mysql存儲例程?存儲例程是存儲在數據庫服務器中的一組sql語句,通過在查詢中調用一個指定的名稱來執行這些sql語句命令。
為什么要使用mysql存儲過程?
我們都知道應用程序分為兩種,一種是基于web,一種是基于桌面,他們都和數據庫進行交互來完成數據的存取工作。假設現在有一種應用程序包含了這兩 種,現在要修改其中的一個查詢sql語句,那么我們可能要同時修改他們中對應的查詢sql語句,當我們的應用程序很龐大很復雜的時候問題就出現這,不易維 護!另外把sql查詢語句放在我們的web程序或桌面中很容易遭到sql注入的破壞。而存儲例程正好可以幫我們解決這些問題。
存儲過程(stored procedure)、存儲例程(store routine)、存儲函數區別
Mysql存儲例程實際包含了存儲過程和存儲函數,它們被統稱為存儲例程。
其中存儲過程主要完成在獲取記錄或插入記錄或更新記錄或刪除記錄,即完成select insert delete update等的工作。而存儲函數只完成查詢的工作,可接受輸入參數并返回一個結果。
創建mysql存儲過程、存儲函數
create procedure 存儲過程名(參數)
存儲過程體
create function 存儲函數名(參數)
下面是存儲過程的例子:

DELIMITER // 
CREATE PROCEDURE proc1(OUT s int)
BEGIN
  SELECT COUNT(*) INTO s FROM user;
END //
DELIMITER ;

注:
(1)這里需要注意的是DELIMITER//DELIMITER;兩句, DELIMITER是分割符的意思,因為MySQL默認以";"為分隔 符,如果我們沒有聲明分割符,那么編譯器會把存儲過程當成SQL語句進行處理,則存儲過程的編譯過程會報錯,所以要事先用DELIMITER關鍵字申明當 前段分隔符,這樣MySQL才會將";"當做存儲過程中的代碼,不會執行這些代碼,用完了之后要把分隔符還原。
(2)存儲過程根據需要可能會有輸入、輸出、輸入輸出參數,這里有一個輸出參數s,類型是int型,如果有多個參數用","分割開。
(3)過程體的開始與結束使用BEGINEND進行標識。
這樣,我們的一個MySQL存儲過程就完成了,是不是很容易呢?看不懂也沒關系,接下來,我們詳細的講解。

(2). 聲明分割符
其實,關于聲明分割符,上面的注解已經寫得很清楚,不需要多說,只是稍微要注意一點的是:如果是用MySQL的Administrator管理工具時,可以直接創建,不再需要聲明。

(3). 參數
MySQL存儲過程的參數用在存儲過程的定義,共有三種參數類型,IN,OUT,INOUT,形式如:
CREATEPROCEDURE 存儲過程名([[IN |OUT |INOUT ] 參數名 數據類形...])
IN 輸入參數:
表示該參數的值必須在調用存儲過程時指定,在存儲過程中修改該參數的值不能被返回,為默認值
OUT 輸出參數:
該值可在存儲過程內部被改變,并可返回
INOUT 輸入輸出參數:
調用時指定,并且可被改變和返回
Ⅰ. IN參數例子
創建:

DELIMITER //  
CREATE PROCEDURE demo_in_parameter(IN p_in int)  
    BEGIN   
    SELECT p_in;   
    SET p_in=2;   
    SELECT p_in;   
    END//  
DELIMITER ; 

執行結果:

1.  mysql > SET @p_in=1;  
2.  mysql > CALL demo_in_parameter(@p_in);  
3.  +------+  
4.  | p_in |  
5.  +------+  
6.  |   1  |   
7.  +------+  
8.   
9.  +------+  
10.| p_in |  
11.+------+  
12.|   2  |   
13.+------+  
14. 
15.mysql> SELECT @p_in;  
16.+-------+  
17.| @p_in |  
18.+-------+  
19.|  1    |  
20.+-------+  

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

Ⅱ.OUT參數例子
創建:

DELIMITER //  
CREATE PROCEDURE demo_out_parameter(OUT p_out int)  
    BEGIN 
    SELECT p_out;  
    SET p_out=
    SELECT p_out;  
    END //  
DELIMITER ; 

執行結果:

1.  mysql > SET @p_out=1;  
2.  mysql > CALL sp_demo_out_parameter(@p_out);  
3.  +-------+  
4.  | p_out |   
5.  +-------+  
6.  | NULL  |   
7.  +-------+  
8.   
9.  +-------+  
10.| p_out |  
11.+-------+  
12.|   2   |   
13.+-------+  
14. 
15.mysql> SELECT @p_out;  
16.+-------+  
17.| p_out |  
18.+-------+  
19.|   2   |  
20.+-------+  

Ⅲ. INOUT參數例子
創建:

DELIMITER //   
CREATE PROCEDURE demo_inout_parameter(INOUT p_inout int)   
BEGIN 
    SELECT p_inout;  
    SET p_inout=2;  
    SELECT p_inout;   
 END //   
DELIMITER ; 

執行結果:

1.  mysql > SET @p_inout=1;  
2.  mysql > CALL demo_inout_parameter(@p_inout) ;  
3.  +---------+  
4.  | p_inout |  
5.  +---------+  
6.  |    1    |  
7.  +---------+  
8.   
9.  +---------+  
10.| p_inout |   
11.+---------+  
12.|    2    |  
13.+---------+  
14. 
15.mysql > SELECT @p_inout;  
16.+----------+  
17.| @p_inout |   
18.+----------+  
19.|    2     |  
20.+----------+ 

(4). 變量
Ⅰ. 變量定義
局部變量聲明一定要放在存儲過程體的開始
DECLAREvariable_name [,variable_name...] datatype [DEFAULT value];
其中,datatype為MySQL的數據類型,如:int, float, date,varchar(length)
例如:

1.  DECLARE l_int int unsigned default 4000000;  
2.  DECLARE l_numeric number(8,2) DEFAULT 9.95;  
3.  DECLARE l_date date DEFAULT '1999-12-31';  
4.  DECLARE l_datetime datetime DEFAULT '1999-12-31 23:59:59';  
5.  DECLARE l_varchar varchar(255) DEFAULT 'This will not be padded';   

Ⅱ. 變量賦值
SET 變量名 = 表達式值 [,variable_name = expression ...]

Ⅲ. 用戶變量

ⅰ. 在MySQL客戶端使用用戶變量
1.  mysql > SELECT 'Hello World' into @x;  
2.  mysql > SELECT @x;  
3.  +-------------+  
4.  |   @x        |  
5.  +-------------+  
6.  | Hello World |  
7.  +-------------+  
8.  mysql > SET @y='Goodbye Cruel World';  
9.  mysql > SELECT @y;  
10.+---------------------+  
11.|     @y              |  
12.+---------------------+  
13.| Goodbye Cruel World |  
14.+---------------------+  
15. 
16.mysql > SET @z=1+2+3;  
17.mysql > SELECT @z;  
18.+------+  
19.| @z   |  
20.+------+  
21.|  6   |  
22.+------+  

ⅱ. 在存儲過程中使用用戶變量

1.  mysql > CREATE PROCEDURE GreetWorld( ) SELECT CONCAT(@greeting,' World');  
2.  mysql > SET @greeting='Hello';  
3.  mysql > CALL GreetWorld( );  
4.  +----------------------------+  
5.  | CONCAT(@greeting,' World') |  
6.  +----------------------------+  
7.  |  Hello World               |  
8.  +----------------------------+  

ⅲ. 在存儲過程間傳遞全局范圍的用戶變量

1.  mysql> CREATE PROCEDURE p1()   SET @last_procedure='p1';  
2.  mysql> CREATE PROCEDURE p2() SELECT CONCAT('Last procedure was ',@last_procedure);  
3.  mysql> CALL p1( );  
4.  mysql> CALL p2( );  
5.  +-----------------------------------------------+  
6.  | CONCAT('Last procedure was ',@last_proc       |  
7.  +-----------------------------------------------+  
8.  | Last procedure was p1                         |  
9.  +-----------------------------------------------+  

注意:
①用戶變量名一般以@開頭
②濫用用戶變量會導致程序難以理解及管理

(5). 注釋


MySQL存儲過程可使用兩種風格的注釋
雙模杠:--
該風格一般用于單行注釋
c風格: 一般用于多行注釋
例如:

DELIMITER //  
CREATE PROCEDURE proc1 (IN parameter1 INTEGER)   
BEGIN   
   DECLARE variable1 CHAR(10);   
   IF parameter1 = 17 THEN   
       SET variable1 = 'birds';   
       ELSE 
       SET variable1 = 'beasts';   
   END IF;   
INSERT INTO table1 VALUES (variable1);  
END //  
DELIMITER ;  

4. MySQL存儲過程的調用
用call和你過程名以及一個括號,括號里面根據需要,加入參數,參數包括輸入參數、輸出參數、輸入輸出參數。具體的調用方法可以參看上面的例子。

5. MySQL存儲過程的查詢
我們像知道一個數據庫下面有那些表,我們一般采用show tables進行查看。那么我們要查看某個數據庫下面的存儲過程,是否也可以采用呢?答案是,我們可以查看某個數據庫下面的存儲過程,但是是令一鐘方式。
我們可以用
selectname from mysql.proc where db=’數據庫名’;
或者
selectroutine_name from information_schema.routines where routine_schema='數據庫名';
或者
showprocedure status where db='數據庫名';
進行查詢。
如果我們想知道,某個存儲過程的詳細,那我們又該怎么做呢?是不是也可以像操作表一樣用describe 表名進行查看呢?
答案是:我們可以查看存儲過程的詳細,但是需要用另一種方法:
SHOWCREATE PROCEDURE 數據庫.存儲過程名;
就可以查看當前存儲過程的詳細。

6. MySQL存儲過程的修改
ALTER PROCEDURE
更改用CREATE PROCEDURE 建立的預先指定的存儲過程,其不會影響相關存儲過程或存儲功能。

7. MySQL存儲過程的刪除
刪除一個存儲過程比較簡單,和刪除表一樣:
DROPPROCEDURE
從MySQL的表格中刪除一個或多個存儲過程。

8. MySQL存儲過程的控制語句
(1). 變量作用域
內部的變量在其作用域范圍內享有更高的優先權,當執行到end。變量時,內部變量消失,此時已經在其作用域外,變量不再可見了,應為在存儲過程外再也不能找到這個申明的變量,但是你可以通過out參數或者將其值指派給會話變量來保存其值。

DELIMITER //  
CREATE PROCEDURE proc3()  
 begin 
   declare x1 varchar(5) default 'outer';  
   begin 
   declare x1 varchar(5) default 'inner';  
   select x
   end;  
   select x
 end //  
DELIMITER ;  

** (2). 條件語句**
Ⅰ. if-then -else語句

DELIMITER //  
CREATE PROCEDURE proc2(IN parameter int)  
  begin 
    declare var int;  
    set var=parameter+
    if var=0 then 
        insert into t values(17);  
    end if; 
    if parameter=0 then 
        update t set s1=s1+
    else 
        update t set s1=s1+
    end if;  
  end //  
DELIMITER ;  

Ⅱ. case語句:

DELIMITER //  
CREATE PROCEDURE proc3 (in parameter int)  
  begin 
    declare var int;  
    set var=parameter+1;  
    case var  
        when 0 then   
          insert into t values(17);  
        when 1 then   
          insert into t values(18);  
        else   
          insert into t values(19);  
    end case;  
  end //  
DELIMITER ; 
case
    when var=0 then
        insert into t values(30);
    when var>0 then
    when var<0 then
    else 
end case

(3). 循環語句
Ⅰ. while ···· end while:

1.  mysql > DELIMITER //  
2.  mysql > CREATE PROCEDURE proc4()  
3.       -> begin 
4.       -> declare var int;  
5.       -> set var=0;  
6.       -> while var<6 do  
7.       -> insert into t values(var);  
8.       -> set var=var+1;  
9.       -> end while;  
10.     -> end;  
11.     -> //  
12.mysql > DELIMITER ; 
 while條件 do
--循環體
endwhile

Ⅱ. repeat···· end repeat:
它在執行操作后檢查結果,而while則是執行前進行檢查。

1.  mysql > DELIMITER //  
2.  mysql > CREATE PROCEDURE proc5 ()  
3.       -> begin   
4.       -> declare v int;  
5.       -> set v=0;  
6.       -> repeat  
7.       -> insert into t values(v);  
8.       -> set v=v+1;  
9.       -> until v>=5  
10.     -> end repeat;  
11.     -> end;  
12.     -> //  
13.mysql > DELIMITER ;  
 repeat
--循環體
until循環條件     
endrepeat;

Ⅲ. loop ·····endloop:
loop循環不需要初始條件,這點和while 循環相似,同時和repeat循環一樣不需要結束條件, leave語句的意義是離開循環。

1.  mysql > DELIMITER //  
2.  mysql > CREATE PROCEDURE proc6 ()  
3.       -> begin 
4.       -> declare v int;  
5.       -> set v=0;  
6.       -> LOOP_LABLE:loop  
7.       -> insert into t values(v);  
8.       -> set v=v+1;  
9.       -> if v >=5 then 
10.     -> leave LOOP_LABLE;  
11.     -> end if;  
12.     -> end loop;  
13.     -> end;  
14.     -> //  
15.mysql > DELIMITER ;  

Ⅳ. LABLES 標號:
標號可以用在begin repeat while 或者loop 語句前,語句標號只能在合法的語句前面使用。可以跳出循環,使運行指令達到復合語句的最后一步。

(4). ITERATE迭代
Ⅰ. ITERATE:

1.    通過引用復合語句的標號,來從新開始復合語句
2.  mysql > DELIMITER //  
3.  mysql > CREATE PROCEDURE proc10 ()  
4.       -> begin 
5.       -> declare v int;  
6.       -> set v=0;  
7.       -> LOOP_LABLE:loop  
8.      -> if v=3 then   
9.      -> set v=v+1;  
10.        -> ITERATE LOOP_LABLE;  
11.        -> end if;  
12.     -> insert into t values(v);  
13.     -> set v=v+1;  
14.        -> if v>=5 then 
15.        -> leave LOOP_LABLE;  
16.     -> end if;  
17.     -> end loop;  
18.     -> end;  
19.     -> //  
20.mysql > DELIMITER ; 

9. MySQL存儲過程的基本函數


(1).字符串類
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開頭,直到字串長度為lengthLTRIM (string2 )

去除前端空格
REPEAT (string2 ,count )
重復count次

REPLACE (str ,search_str ,replace_str )
在str中用replace_str替換search_str

RPAD (string2 ,length ,pad)
在str后用pad補充,直到長度為lengthRTRIM (string2 )
去除后端空格

STRCMP (string1 ,string2 )
逐字符比較兩字串大小,
SUBSTRING (str , position [,length ])
從str的position開始,取length個字符,注:mysql中處理字符串時,默認第一個字符下標為1,即參數position必須大于等于1

1.  mysql> select substring('abcd',0,2);  
2.  +-----------------------+  
3.  | substring('abcd',0,2) |  
4.  +-----------------------+  
5.  |                       |  
6.  +-----------------------+  
7.  1 row in set (0.00 sec)  
8.   
9.  mysql> select substring('abcd',1,2);  
10.+-----------------------+  
11.| substring('abcd',1,2) |  
12.+-----------------------+  
13.|     ab                |  
14.+-----------------------+  
15.1 row in set (0.02 sec)  

TRIM([[BOTH|LEADING|TRAILING][padding] FROM]string2)
去除指定位置的指定字符

UCASE (string2 )
轉換成大寫

RIGHT(string2,length)
取string2最后length個字符

SPACE(count)
生成count個空格

(2).數學類
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)默認變為整形值

1.  mysql> select round(1.23);  
2.  +-------------+  
3.  | round(1.23) |  
4.  +-------------+  
5.  |           1 |  
6.  +-------------+  
7.  1 row in set (0.00 sec)  
8.   
9.  mysql> select round(1.56);  
10.+-------------+  
11.| round(1.56) |  
12.+-------------+  
13.|           2 |  
14.+-------------+  
15.1 row in set (0.00 sec) 

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

1.  mysql> select round(1.567,2);  
2.  +----------------+  
3.  | round(1.567,2) |  
4.  +----------------+  
5.  |           1.57 |  
6.  +----------------+  
7.  1 row in set (0.00 sec) 
SIGN (number2 ) //

(3).日期時間類
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)
分返回符號,正負或0

SQRT(number2)
開平方

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內容