mysql存儲過程詳解
前端
1.存儲過程簡介mysql
咱們經常使用的操做數據庫語言SQL語句在執行的時候須要要先編譯,而後執行,而存儲過程(Stored Procedure)是一組爲了完成特定功能的SQL語句集,經編譯後存儲在數據庫中,用戶經過指定存儲過程的名字並給定參數(若是該存儲過程帶有參數)來調用執行它。sql
一個存儲過程是一個可編程的函數,它在數據庫中建立並保存。它能夠有SQL語句和一些特殊的控制結構組成。當但願在不一樣的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是很是有用的。數據庫中的存儲過程能夠看作是對編程中面向對象方法的模擬。它容許控制數據的訪問方式。數據庫
存儲過程一般有如下優勢:express
(1).存儲過程加強了SQL語言的功能和靈活性。存儲過程能夠用流控制語句編寫,有很強的靈活性,能夠完成複雜的判斷和較複雜的運算。編程
(2).存儲過程容許標準組件是編程。存儲過程被建立後,能夠在程序中被屢次調用,而沒必要從新編寫該存儲過程的SQL語句。並且數據庫專業人員能夠隨時對存儲過程進行修改,對應用程序源代碼毫無影響。後端
(3).存儲過程能實現較快的執行速度。若是某一操做包含大量的Transaction-SQL代碼或分別被屢次執行,那麼存儲過程要比批處理的執行速度快不少。由於存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,而且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。安全
(4).存儲過程能過減小網絡流量。針對同一個數據庫對象的操做(如查詢、修改),若是這一操做所涉及的Transaction-SQL語句被組織程存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大增長了網絡流量並下降了網絡負載。網絡
(5).存儲過程可被做爲一種安全機制來充分利用。系統管理員經過執行某一存儲過程的權限進行限制,可以實現對相應的數據的訪問權限的限制,避免了非受權用戶對數據的訪問,保證了數據的安全。ide
2.關於MySQL的存儲過程
存儲過程是數據庫存儲的一個重要的功能,可是MySQL在5.0之前並不支持存儲過程,這使得MySQL在應用上大打折扣。好在MySQL 5.0終於開始已經支持存儲過程,這樣便可以大大提升數據庫的處理速度,同時也能夠提升數據庫編程的靈活性。
3.MySQL存儲過程的建立
(1).格式
MySQL存儲過程建立的格式:CREATE PROCEDURE過程名([過程參數[,...]])
[特性...]過程體
這裏先舉個例子:
mysql> DELIMITER //
mysql> CREATEPROCEDUREproc1(OUTs int)
-> BEGIN
-> SELECTCOUNT(*) INTOs FROMuser;
-> END
-> //
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參數例子
建立:
mysql > DELIMITER //
mysql > CREATEPROCEDUREdemo_in_parameter(INp_in int)
-> BEGIN
-> SELECTp_in;
-> SETp_in=2;
-> SELECTp_in;
-> END;
-> //
mysql > DELIMITER ;
執行結果:
mysql > SET@p_in=1;
mysql > CALL demo_in_parameter(@p_in);
+------+
| p_in |
+------+
| 1 |
+------+
+------+
| p_in |
+------+
| 2 |
+------+
mysql> SELECT@p_in;
+-------+
| @p_in |
+-------+
| 1 |
+-------+
以上能夠看出,p_in雖然在存儲過程當中被修改,但並不影響@p_id的值
Ⅱ.OUT參數例子
建立:
mysql > DELIMITER //
mysql > CREATEPROCEDUREdemo_out_parameter(OUTp_out int)
-> BEGIN
-> SELECTp_out;
-> SETp_out=2;
-> SELECTp_out;
-> END;
-> //
mysql > DELIMITER ;
執行結果:
mysql > SET@p_out=1;
mysql > CALL sp_demo_out_parameter(@p_out);
+-------+
| p_out |
+-------+
| NULL|
+-------+
+-------+
| p_out |
+-------+
| 2 |
+-------+
mysql> SELECT@p_out;
+-------+
| p_out |
+-------+
| 2 |
+-------+
Ⅲ. INOUT參數例子
建立:
mysql > DELIMITER //
mysql > CREATEPROCEDUREdemo_inout_parameter(INOUT p_inout int)
-> BEGIN
-> SELECTp_inout;
-> SETp_inout=2;
-> SELECTp_inout;
-> END;
-> //
mysql > DELIMITER ;
mysql >SET @p_inout=1;
mysql >CALL demo_inout_parameter(@p_inout) ;
+---------+
| p_inout |
+---------+
| 1 |
+---------+
+---------+
| p_inout |
+---------+
| 2 |
+---------+
mysql >SELECT @p_inout;
+----------+
| @p_inout |
+----------+
| 2 |
+----------+
(4).變量
Ⅰ.變量定義
DECLARE variable_name [,variable_name...] datatype [DEFAULT value];
其中,datatype爲MySQL的數據類型,如:int, float, date, varchar(length)
例如:
DECLAREl_int intunsigned default4000000;
DECLAREl_numeric number(8,2) DEFAULT9.95;
DECLAREl_date dateDEFAULT'1999-12-31';
DECLAREl_datetime datetime DEFAULT'1999-12-31 23:59:59';
DECLAREl_varchar varchar(255) DEFAULT'This will not be padded';
SET變量名=表達式值[,variable_name = expression ...]
Ⅲ.用戶變量
ⅰ.在MySQL客戶端使用用戶變量
mysql > SELECT'Hello World'into@x;
mysql > SELECT@x;
+-------------+
| @x |
+-------------+
| Hello World|
+-------------+
mysql > SET@y='Goodbye Cruel World';
mysql > SELECT@y;
+---------------------+
| @y |
+---------------------+
| Goodbye Cruel World |
+---------------------+
mysql > SET@z=1+2+3;
mysql > SELECT@z;
+------+
| @z |
+------+
| 6 |
+------+
ⅱ.在存儲過程當中使用用戶變量
mysql > CREATEPROCEDUREGreetWorld( ) SELECTCONCAT(@greeting,' World');
mysql > SET@greeting='Hello';
mysql > CALL GreetWorld( );
+----------------------------+
| CONCAT(@greeting,' World') |
+----------------------------+
| Hello World |
+----------------------------+
mysql> CREATEPROCEDUREp1() SET@last_procedure='p1';
mysql> CREATEPROCEDUREp2() SELECTCONCAT('Last procedure was ',@last_proc);
mysql> CALL p1( );
mysql> CALL p2( );
+-----------------------------------------------+
| CONCAT('Last procedure was ',@last_proc |
+-----------------------------------------------+
| Lastprocedurewas p1 |
+-----------------------------------------------+
①用戶變量名通常以@開頭
②濫用用戶變量會致使程序難以理解及管理
(5).註釋
MySQL存儲過程可以使用兩種風格的註釋
雙模槓:--
該風格通常用於單行註釋
c風格:通常用於多行註釋
例如:
mysql > DELIMITER //
mysql > CREATEPROCEDUREproc1 --name存儲過程名
-> (INparameter1 INTEGER)
-> BEGIN
-> DECLAREvariable1 CHAR(10);
-> IF parameter1 = 17 THEN
-> SETvariable1 = 'birds';
-> ELSE
-> SETvariable1 = 'beasts';
-> ENDIF;
-> INSERTINTOtable1 VALUES(variable1);
-> END
-> //
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參數或者將其值指派
給會話變量來保存其值。
mysql > DELIMITER //
mysql > CREATEPROCEDUREproc3()
-> begin
-> declarex1 varchar(5) default'outer';
-> begin
-> declarex1 varchar(5) default'inner';
-> selectx1;
-> end;
-> selectx1;
-> end;
-> //
mysql > DELIMITER ;
(2).條件語句
Ⅰ. if-then -else語句
mysql > DELIMITER //
mysql > CREATEPROCEDUREproc2(INparameter int)
-> begin
-> declarevar int;
-> setvar=parameter+1;
-> if var=0 then
-> insertintot values(17);
-> endif;
-> if parameter=0 then
-> updatet sets1=s1+1;
-> else
-> updatet sets1=s1+2;
-> endif;
-> end;
-> //
mysql > DELIMITER ;
Ⅱ. case語句:
mysql > DELIMITER //
mysql > CREATEPROCEDUREproc3 (inparameter int)
-> begin
-> declarevar int;
-> setvar=parameter+1;
-> casevar
-> when0 then
-> insertintot values(17);
-> when1 then
-> insertintot values(18);
-> else
-> insertintot values(19);
-> endcase;
-> end;
-> //
mysql > DELIMITER ;
(3).循環語句
Ⅰ. while ···· end while:
mysql > DELIMITER //
mysql > CREATEPROCEDUREproc4()
-> begin
-> declarevar int;
-> setvar=0;
-> while var<6 do
-> insertintot values(var);
-> setvar=var+1;
-> endwhile;
-> end;
-> //
mysql > DELIMITER ;
Ⅱ. repeat···· end repeat:
它在執行操做後檢查結果,而while則是執行前進行檢查。
mysql > DELIMITER //
mysql > CREATEPROCEDUREproc5 ()
-> begin
-> declarev int;
-> setv=0;
-> repeat
-> insertintot values(v);
-> setv=v+1;
-> until v>=5
-> endrepeat;
-> end;
-> //
mysql > DELIMITER ;
Ⅲ. loop ·····end loop:
loop循環不須要初始條件,這點和while循環類似,同時和repeat循環同樣不須要結束條件, leave語句的意義是離開循環。
mysql > DELIMITER //
mysql > CREATEPROCEDUREproc6 ()
-> begin
-> declarev int;
-> setv=0;
-> LOOP_LABLE:loop
-> insertintot values(v);
-> setv=v+1;
-> if v >=5 then
-> leave LOOP_LABLE;
-> endif;
-> endloop;
-> end;
-> //
mysql > DELIMITER ;
Ⅳ. LABLES標號:
標號能夠用在begin repeat while或者loop語句前,語句標號只能在合法的語句前面使用。能夠跳出循環,使運行指令達到複合語句的最後一步。
(4). ITERATE迭代
Ⅰ. ITERATE:
經過引用複合語句的標號,來重新開始複合語句
mysql > DELIMITER //
mysql > CREATEPROCEDUREproc10 ()
-> begin
-> declarev int;
-> setv=0;
-> LOOP_LABLE:loop
-> if v=3 then
-> setv=v+1;
-> ITERATE LOOP_LABLE;
-> endif;
-> insertintot values(v);
-> setv=v+1;
-> if v>=5 then
-> leave LOOP_LABLE;
-> endif;
-> endloop;
-> end;
-> //
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
mysql> selectsubstring('abcd',0,2);
+-----------------------+
| substring('abcd',0,2) |
+-----------------------+
| |
+-----------------------+
1 row inset(0.00 sec)
mysql> selectsubstring('abcd',1,2);
+-----------------------+
| substring('abcd',1,2) |
+-----------------------+
| ab |
+-----------------------+
1 row inset(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)默認變爲×××值
mysql> selectround(1.23);
+-------------+
| round(1.23) |
+-------------+
| 1 |
+-------------+
1 row inset(0.00 sec)
mysql> selectround(1.56);
+-------------+
| round(1.56) |
+-------------+
| 2 |
+-------------+
1 row inset(0.00 sec)
(2)能夠設定小數位數,返回浮點型數據
mysql> selectround(1.567,2);
+----------------+
| round(1.567,2) |
+----------------+
| 1.57 |
+----------------+
1 row inset(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) //開平方