MySql儲存過程的作用及語法

OldBoy~發表於2017-05-17

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()$

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$

相關文章