MySQL儲存過程詳解 mysql 儲存過程

leintor發表於2016-07-26
mysql儲存過程詳解

1.      儲存過程簡介
 
我們常用的運算元據庫語言SQL語句在執行的時候需要要先編譯,然後執行,而儲存過程(Stored Procedure)是一組為了完成特定功能的SQL語句集,經編譯後儲存在資料庫中,使用者透過指定儲存過程的名字並給定引數(如果該儲存過程帶有引數)來呼叫執行它。
一個儲存過程是一個可程式設計的函式,它在資料庫中建立並儲存。它可以有SQL語句和一些特殊的控制結構組成。當希望在不同的應用程式或平臺上執行相同的函式,或者封裝特定功能時,儲存過程是非常有用的。資料庫中的儲存過程可以看做是對程式設計中物件導向方法的模擬。它允許控制資料的訪問方式。
儲存過程通常有以下優點:
(1).儲存過程增強了SQL語言的功能和靈活性。儲存過程可以用流控制語句編寫,有很強的靈活性,可以完成複雜的判斷和較複雜的運算。
(2).儲存過程允許標準元件是程式設計。儲存過程被建立後,可以在程式中被多次呼叫,而不必重新編寫該儲存過程的SQL語句。而且資料庫專業人員可以隨時對儲存過程進行修改,對應用程式原始碼毫無影響。
(3).儲存過程能實現較快的執行速度。如果某一操作包含大量的Transaction-SQL程式碼或分別被多次執行,那麼儲存過程要比批處理的執行速度快很多。因為儲存過程是預編譯的。在首次執行一個儲存過程時查詢,最佳化器對其進行分析最佳化,並且給出最終被儲存在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次執行時都要進行編譯和最佳化,速度相對要慢一些。
(4).儲存過程能過減少網路流量。針對同一個資料庫物件的操作(如查詢、修改),如果這一操作所涉及的Transaction-SQL語句被組織程儲存過程,那麼當在客戶計算機上呼叫該儲存過程時,網路中傳送的只是該呼叫語句,從而大大增加了網路流量並降低了網路負載。
(5).儲存過程可被作為一種安全機制來充分利用。系統管理員透過執行某一儲存過程的許可權進行限制,能夠實現對相應的資料的訪問許可權的限制,避免了非授權使用者對資料的訪問,保證了資料的安全。
 
2.      關於MySQL的儲存過程
儲存過程是資料庫儲存的一個重要的功能,但是MySQL在5.0以前並不支援儲存過程,這使得MySQL在應用上大打折扣。好在MySQL 5.0終於開始已經支援儲存過程,這樣即可以大大提高資料庫的處理速度,同時也可以提高資料庫程式設計的靈活性。

3.      MySQL儲存過程的建立
(1). 格式
MySQL儲存過程建立的格式:CREATE PROCEDURE 過程名 ([過程引數[,...]])
[特性 ...] 過程體
這裡先舉個例子:
1. mysql> DELIMITER //  
2. mysql> CREATE PROCEDURE proc1(OUT s int)  
3.    -> BEGIN 
4.    -> SELECT COUNT(*) INTO s FROM user;  
5.    -> END 
6.    -> //  
7. mysql> DELIMITER ; 
 
注:
(1)這裡需要注意的是DELIMITER //和DELIMITER ;兩句,DELIMITER是分割符的意思,因為MySQL預設以";"為分隔符,如果我們沒有宣告分割符,那麼編譯器會把儲存過程當成SQL語句進行處理,則儲存過程的編譯過程會報錯,所以要事先用DELIMITER關鍵字申明當前段分隔符,這樣MySQL才會將";"當做儲存過程中的程式碼,不會執行這些程式碼,用完了之後要把分隔符還原。
(2)儲存過程根據需要可能會有輸入、輸出、輸入輸出引數,這裡有一個輸出引數s,型別是int型,如果有多個引數用","分割開。
(3)過程體的開始與結束使用BEGIN與END進行標識。
這樣,我們的一個MySQL儲存過程就完成了,是不是很容易呢?看不懂也沒關係,接下來,我們詳細的講解。
 
(2). 宣告分割
其實,關於宣告分割符,上面的註解已經寫得很清楚,不需要多說,只是稍微要注意一點的是:如果是用MySQL的Administrator管理工具時,可以直接建立,不再需要宣告。
 
(3). 引數
MySQL儲存過程的引數用在儲存過程的定義,共有三種引數型別,IN,OUT,INOUT,形式如:
CREATE PROCEDURE([[IN |OUT |INOUT ] 引數名 資料類形...])
IN 輸入引數:表示該引數的值必須在呼叫儲存過程時指定,在儲存過程中修改該引數的值不能被返回,為預設值
OUT 輸出引數:該值可在儲存過程內部被改變,並可返回
INOUT 輸入輸出引數:呼叫時指定,並且可被改變和返回
Ⅰ. IN引數例子
建立:
1. mysql > DELIMITER //  
2. mysql > CREATE PROCEDURE demo_in_parameter(IN p_in int)  
3. -> BEGIN   
4. -> SELECT p_in;   
5. -> SET p_in=2;   
6. -> SELECT p_in;   
7. -> END;   
8. -> //  
9. mysql > 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引數例子
建立:
1. mysql > DELIMITER //  
2. mysql > CREATE PROCEDURE demo_out_parameter(OUT p_out int)  
3. -> BEGIN 
4. -> SELECT p_out;  
5. -> SET p_out=2;  
6. -> SELECT p_out;  
7. -> END;  
8. -> //  
9. mysql > 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引數例子
建立:

1. mysql > DELIMITER //   
2. mysql > CREATE PROCEDURE demo_inout_parameter(INOUT p_inout int)   
3. -> BEGIN 
4. -> SELECT p_inout;  
5. -> SET p_inout=2;  
6. -> SELECT p_inout;   
7. -> END;  
8. -> //   
9. mysql > 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). 變數
Ⅰ. 變數定義
DECLARE variable_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_proc);  
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風格: 一般用於多行註釋
例如:
1. mysql > DELIMITER //  
2. mysql > CREATE PROCEDURE proc1 --name儲存過程名  
3. -> (IN parameter1 INTEGER)   
4. -> BEGIN   
5. -> DECLARE variable1 CHAR(10);   
6. -> IF parameter1 = 17 THEN   
7. -> SET variable1 = 'birds';   
8. -> ELSE 
9. -> SET variable1 = 'beasts';   
10. -> END IF;   
11. -> INSERT INTO table1 VALUES (variable1);  
12. -> END   
13. -> //  
14. mysql > DELIMITER ;  
 
4.      MySQL儲存過程的呼叫
用call和你過程名以及一個括號,括號裡面根據需要,加入引數,引數包括輸入引數、輸出引數、輸入輸出引數。具體的呼叫方法可以參看上面的例子。

5.      MySQL儲存過程的查詢
我們像知道一個資料庫下面有那些表,我們一般採用show tables;進行檢視。那麼我們要檢視某個資料庫下面的儲存過程,是否也可以採用呢?答案是,我們可以檢視某個資料庫下面的儲存過程,但是是令一鍾方式。
我們可以用
select name from mysql.proc where db=’資料庫名’;
或者
select routine_name from information_schema.routines where routine_schema='資料庫名';
或者
show procedure status where db='資料庫名';
進行查詢。
如果我們想知道,某個儲存過程的詳細,那我們又該怎麼做呢?是不是也可以像操作表一樣用describe 表名進行檢視呢?
答案是:我們可以檢視儲存過程的詳細,但是需要用另一種方法:
SHOW CREATE PROCEDURE 資料庫.儲存過程名;
就可以檢視當前儲存過程的詳細。
 
6.      MySQL儲存過程的修改
ALTER PROCEDURE
更改用CREATE PROCEDURE 建立的預先指定的儲存過程,其不會影響相關儲存過程或儲存功能。
 
7.      MySQL儲存過程的刪除
刪除一個儲存過程比較簡單,和刪除表一樣:
DROP PROCEDURE
從MySQL的表格中刪除一個或多個儲存過程。
 
8.      MySQL儲存過程的控制語句
(1). 變數作用域
內部的變數在其作用域範圍內享有更高的優先權,當執行到end。變數時,內部變數消失,此時已經在其作用域外,變數不再可見了,應為在儲存
過程外再也不能找到這個申明的變數,但是你可以透過out引數或者將其值指派
給會話變數來儲存其值。

1. mysql > DELIMITER //  
2. mysql > CREATE PROCEDURE proc3()  
3.     -> begin 
4.     -> declare x1 varchar(5) default 'outer';  
5.     -> begin 
6.     -> declare x1 varchar(5) default 'inner';  
7.     -> select x1;  
8.     -> end;  
9.     -> select x1;  
10.     -> end;  
11.     -> //  
12. mysql > DELIMITER ;  
 
 (2). 條件語句
Ⅰ. if-then -else語句

1. mysql > DELIMITER //  
2. mysql > CREATE PROCEDURE proc2(IN parameter int)  
3.     -> begin 
4.     -> declare var int;  
5.     -> set var=parameter+1;  
6.     -> if var=0 then 
7.     -> insert into t values(17);  
8.     -> end if;  
9.     -> if parameter=0 then 
10.     -> update t set s1=s1+1;  
11.     -> else 
12.     -> update t set s1=s1+2;  
13.     -> end if;  
14.     -> end;  
15.     -> //  
16. mysql > DELIMITER ;  

Ⅱ. case語句: 

1. mysql > DELIMITER //  
2. mysql > CREATE PROCEDURE proc3 (in parameter int)  
3.     -> begin 
4.     -> declare var int;  
5.     -> set var=parameter+1;  
6.     -> case var  
7.     -> when 0 then   
8.     -> insert into t values(17);  
9.     -> when 1 then   
10.     -> insert into t values(18);  
11.     -> else   
12.     -> insert into t values(19);  
13.     -> end case;  
14.     -> end;  
15.     -> //  
16. mysql > DELIMITER ; 
 
(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 ; 

Ⅱ. 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 ;  

Ⅲ. loop ·····end loop:
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. mysql > DELIMITER //  
2. mysql > CREATE PROCEDURE proc10 ()  
3.     -> begin 
4.     -> declare v int;  
5.     -> set v=0;  
6.     -> LOOP_LABLE:loop  
7.     -> if v=3 then   
8.     -> set v=v+1;  
9.     -> ITERATE LOOP_LABLE;  
10.     -> end if;  
11.     -> insert into t values(v);  
12.     -> set v=v+1;  
13.     -> if v>=5 then 
14.     -> leave LOOP_LABLE;  
15.     -> end if;  
16.     -> end loop;  
17.     -> end;  
18.     -> //  
19. 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開頭,直到字串長度為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 

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) //開平方

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/20200170/viewspace-2122553/,如需轉載,請註明出處,否則將追究法律責任。

相關文章