MySQL使用儲存過程的作用
1、使用了存過程,很多相似性的刪除,更新,新增等操作就變得輕鬆了,並且以後也便於管理!
2、儲存過程因為SQL語句已經預編繹過了,因此執行的速度比較快。
3、儲存過程可以接受引數、輸出引數、返回單個或多個結果集以及返回值。可以向程式返回錯誤原因。
4、儲存過程執行比較穩定,不會有太多的錯誤。只要一次成功,以後都會按這個程式執行。
5、儲存過程主要是在伺服器上執行,減少對客戶機的壓力。
6、儲存過程可以包含程式流、邏輯以及對資料庫的查詢。同時可以實體封裝和隱藏了資料邏輯。
7、儲存過程可以在單個儲存過程中執行一系列SQL語句。
8、儲存過程可以從自己的儲存過程內引用其它儲存過程,這可以簡化一系列複雜語句。
MySQL儲存過程的建立
先定義一個結束分隔符,控制sql語句的執行
delimiter $ //意思是用$作為sql語句的結束符
引數
MySQL儲存過程的引數用在儲存過程的定義,共有三種引數型別,IN,OUT,INOUT,形式如:
CREATE PROCEDURE([[IN |OUT |INOUT ] 引數名 資料類形...])
IN 輸入引數:表示該引數的值必須在呼叫儲存過程時指定,在儲存過程中修改該引數的值不能被返回,為預設值
OUT 輸出引數:該值可在儲存過程內部被改變,並可返回
INOUT 輸入輸出引數:呼叫時指定,並且可被改變和返回
①IN引數例子
建立:
DELIMITER $ CREATE PROCEDURE demo(IN p_in int) BEGIN SELECT p_in; SET p_in=2; SELECT p_in; END$
執行結果:
SET @p_in=1; CALL demo(@p_in); +------+ | p_in | +------+ | 1 | +------+ +------+ | p_in | +------+ | 2 | +------+ SELECT @p_in; +-------+ | @p_in | +-------+ | 1 | +-------+
以上可以看出,p_in雖然在儲存過程中被修改,但並不影響@p_id的值
②OUT引數例子
建立:
DELIMITE $ CREATE PROCEDURE demo(OUT p_out int) BEGIN SELECT p_out; SET p_out=2; SELECT p_out; END$
執行結果:
SET @p_out=1; CALL demo(@p_out); +-------+ | p_out | +-------+ | NULL | +-------+ +-------+ | p_out | +-------+ | 2 | +-------+ SELECT @p_out; +-------+ | p_out | +-------+ | 2 | +-------+
③INOUT引數例子
建立:
DELIMITER $ CREATE PROCEDURE demo_inout_parameter(INOUT p_inout int) BEGIN SELECT p_inout; SET p_inout=2; SELECT p_inout; END$
執行結果:
SET @p_inout=1; CALL demo_inout_parameter(@p_inout) ; +---------+ | p_inout | +---------+ | 1 | +---------+ +---------+ | p_inout | +---------+ | 2 | +---------+ SELECT @p_inout; +----------+ | @p_inout | +----------+ | 2 | +----------+
變數
①定義變數
例如:
DECLARE l_int int unsigned default 4000000; DECLARE l_numeric number(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';
②變數賦值
SET 變數名 = 表示式值 [,variable_name = expression ...]
③使用者變數
ⅰ. 在MySQL客戶端使用使用者變數
SELECT 'Hello World' into @x; SELECT @x; +-------------+ | @x | +-------------+ | Hello World | +-------------+ SET @y='Goodbye Cruel World'; SELECT @y; +---------------------+ | @y | +---------------------+ | Goodbye Cruel World | +---------------------+ SET @z=1+2+3; SELECT @z; +------+ | @z | +------+ | 6 | +------+
ⅱ. 在儲存過程中使用使用者變數
CREATE PROCEDURE GreetWorld( ) BEGIN SELECT CONCAT(@greeting,' World'); SET @greeting='Hello'; END$ CALL GreetWorld( ); +----------------------------+ | CONCAT(@greeting,' World') | +----------------------------+ | Hello World | +----------------------------+
④MySQL儲存過程的修改
ALTER PROCEDURE
更改用CREATE PROCEDURE 建立的預先指定的儲存過程,其不會影響相關儲存過程或儲存功能。
⑤MySQL儲存過程的刪除
刪除一個儲存過程比較簡單,和刪除表一樣:
DROP PROCEDURE
從MySQL的表格中刪除一個或多個儲存過程。
⑥MySQL儲存過程的控制語句
(1). 變數作用域
內部的變數在其作用域範圍內享有更高的優先權,當執行到end。變數時,內部變數消失,此時已經在其作用域外,變數不再可見了,應為在儲存
過程外再也不能找到這個申明的變數,但是你可以通過out引數或者將其值指派
給會話變數來儲存其值。
CREATE PROCEDURE proc3() begin declare x1 varchar(5) default 'outer'; begin declare x1 varchar(5) default 'inner'; select x1; end; select x1; end$
(2). 條件語句
A:if-then -else語句
CREATE PROCEDURE proc2(IN parameter int) begin declare var int; set var=parameter+1; if var=0 then insert into t values(17); end if; if parameter=0 then update t set s1=s1+1; else update t set s1=s1+2; end if; end$
B:case語句:
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$
C:loop ·····end loop:
loop迴圈不需要初始條件,這點和while 迴圈相似,同時和repeat迴圈一樣不需要結束條件, leave語句的意義是離開迴圈。
CREATE PROCEDURE proc6 () begin declare v int; set v=0; LOOP_LABLE:loop insert into t values(v); set v=v+1; if v >=5 then leave LOOP_LABLE; end if; end loop; end$
D:while語句 while ···· end while:
CREATE PROCEDURE proc4() begin declare var int; set var=0; while var<6 do insert into t values(var); set var=var+1; end while; end$
E:repeat 語句 repeat···· end repeat:
它在執行操作後檢查結果,而while則是執行前進行檢查。
CREATE PROCEDURE proc5 () begin declare v int; set v=0; repeat insert into t values(v); set v=v+1; until v>=5 end repeat; end$
⑦ITERATE迭代
ITERATE:
通過引用複合語句的標號,來從新開始複合語句
CREATE PROCEDURE proc10 () begin declare v int; set v=0; LOOP_LABLE:loop if v=3 then set v=v+1; ITERATE LOOP_LABLE; end if; insert into t values(v); set v=v+1; if v>=5 then leave LOOP_LABLE; end if; end loop; end$
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
select substring('abcd',0,2); +-----------------------+ | substring('abcd',0,2) | +-----------------------+ +-----------------------+ select substring('abcd',1,2); +-----------------------+ | substring('abcd',1,2) | +-----------------------+ | ab | +-----------------------+ 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)預設變為整形值
select round(1.23); +-------------+ | round(1.23) | +-------------+ | 1 | +-------------+ select round(1.56); +-------------+ | round(1.56) | +-------------+ | 2 | +-------------+
(2)可以設定小數位數,返回浮點型資料
select round(1.567,2); +----------------+ | round(1.567,2) | +----------------+ | 1.57 | +----------------+
(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) //小時
視訊學習中的例子
1
create procedure p1() begin select 'hello' from dual; end$ call p1()$
2
create procedure p2() begin declare age int default 18; declare height int default 180; select concat('年齡是',age,'身高是',height); end$
3
create procedure p3() begin declare age int default 18; set age:= age+20; select concat('20年後年齡是',age); end$
4
create procedure p4() begin declare age int default 18; if age >=18 then select '成年'; else select '未成年'; end if; end$
5
create procedure p5(width int ,height int) begin select concat('你的面積是', width * height ) as area; if width >height then select '你挺胖';; elseif width < height then select ‘你挺瘦’; else select '你挺方'; endif; end$
6
create procedure p6() begin declare total int default 0; declare num int default 0; while num <100 do set num:=num+1; set total:= total +num; end while; select total; end$
7
create procedure p7(in n int) begin declare total int default 0; declare num int default 0; while num <n do set num:=num+1; set total:= total +num; end while; select total; end$
8
create procedure p8(in n int ,out total int) begin declare num int default 0; set total :=0; #null 碰到任何操作都會變成null while num<n do set num:=num+1; set total :=total+num; end while; end$ call p8(100,@summary)$ select @summary
9
create procedure p9(inout age int) begin set age:=age +20; end$ set @currage =18$ call p9(@currage)$ select @currage$
10
create procedure p10() begin declare pos int default 0; set pos := floor(5*rand()); case pos when 1 then select 'still flying'; when 2 then select 'fall in sea'; when 3 then select 'in the island'; else select 'I don't know'; end case; end$
11
create procedure p11() begin declare total int default 0; declare i int default 0; repeat set i:=i+1; set total :=total +i; until i>=100 end repeat; select total; end$
12 遊標
create procedure p12() begin declare row_gid int; declare row_num int; declare row_name varchar(20); declare getgoods cursor for select gid,num,name from goods; open getgoods; fetch getgoods into row_gid,row_num,row_name; select row_num,row_name; close getgoods; end$
13
create procedure p13() begin declare row_gid int; declare row_num int; declare row_name varchar(20); declare getgoods cursor for select gid, num , name from goods; open getgoods; fetch getgoods into row_gid,row_num,row_name; #cat select row_num,row_name; fetch getgoods into row_gid,row_num,row_name;#dog select row_num,row_name; fetch getgoods into row_gid,row_num,row_name;#pig select row_num,row_name; fetch getgoods into row_gid,row_num,row_name;#error select row_num,row_name; close getgoods; end$
#邏輯處理遊標越界
14
create procedure p14() begin declare row_gid int; declare row_num int; declare row_name varchar(20); declare cnt int default 0; declare i int default 0; declare getgoods cursor for select gid, num , name from goods; select count(*) into cnt from goods; open getgoods; repeat set fetch getgoods into row_gid,row_num,row_name; #cat select row_num,row_name; until i >= cnt end repeat; close getgoods; end$
15
遊標越界的時候,在mysql cursor中有一個標示,可以declare continue handler 來操作一個越界標示
declare continue handler for NOT FOUND statement; create procedure p15() begin declare row_gid int; declare row_num int; declare row_name varchar(20); declare you int default 1; declare getgoods cursor for select gid, num , name from goods; select count(*) into cnt from goods; declare continue handler for NOT FOUND set you :=0; //如果發生not found事件,把you 改為 0 open getgoods; repeat set fetch getgoods into row_gid,row_num,row_name; select row_num,row_name; until you=0 end repeat; close getgoods; end$ call p15()$ show warnings$
16:上條BUG修復,continue和 exit的區別(exit觸發後後面的程式碼不在執行,而continue繼續執行)
create procedure p16() begin declare row_gid int; declare row_num int; declare row_name varchar(20); declare you int default 1; declare getgoods cursor for select gid, num , name from goods; select count(*) into cnt from goods; declare exit handler for NOT FOUND set you :=0;#這裡的handler型別改成了exit open getgoods; repeat set fetch getgoods into row_gid,row_num,row_name; select row_num,row_name; until you=0 end repeat; close getgoods; end$
17:正確嚴謹的邏輯
#接下來的儲存過程才應該是遊標的正確使用方式:
#一定要用continue handler ,通過邏輯來控制。
create procedure p17() begin declare row_gid int; declare row_num int; declare row_name varchar(20); declare you int default 1; declare getgoods cursor for select gid, num , name from goods; select count(*) into cnt from goods; declare continue handler for NOT FOUND set you :=0; open getgoods; fetch getgoods into row_gid,row_num,row_name; repeat set select row_num,row_name; fetch getgoods into row_gid,row_num,row_name; until you=0 end repeat; close getgoods; end$
#換成while 迴圈
18
create procedure p18() begin declare row_gid int; declare row_num int; declare row_name varchar(20); declare you int default 1; declare getgoods cursor for select gid, num , name from goods; select count(*) into cnt from goods; declare continue handler for NOT FOUND set you :=0; open getgoods; fetch getgoods into row_gid,row_num,row_name; while you =1 do select row_num,row_name; fetch getgoods into row_gid,row_num,row_name; end while; close getgoods; end$