mysql存儲過程和存儲函數

11.png

22.png

 

 

1.      存儲過程簡介mysql

 操做數據庫語言SQL語句在執行的時候須要要先編譯,而後執行,sql

而存儲過程(Stored Procedure)是一組爲了完成特定功能的SQL語句集,經編譯後存儲在數據庫中,用戶經過指定存儲過程的名字並給定參數(若是該存儲過程帶有參數)來調用執行它。數據庫

一個存儲過程是一個可編程的函數,它在數據庫中建立並保存。它能夠有SQL語句和一些特殊的控制結構組成。當但願在不一樣的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是很是有用的。數據庫中的存儲過程能夠看作是對編程中面向對象方法的模擬。它容許控制數據的訪問方式。express

存儲過程優勢:編程

(1).存儲過程加強了SQL語言的功能和靈活性。存儲過程能夠用流控制語句編寫,有很強的靈活性,能夠完成複雜的判斷和較複雜的運算。安全

(2).存儲過程容許標準組件是編程。存儲過程被建立後,能夠在程序中被屢次調用,而沒必要從新編寫該存儲過程的SQL語句。並且數據庫專業人員能夠隨時對存儲過程進行修改,對應用程序源代碼毫無影響。網絡

(3).存儲過程能實現較快的執行速度。若是某一操做包含大量的Transaction-SQL代碼或分別被屢次執行,那麼存儲過程要比批處理的執行速度快不少。由於存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,而且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。函數

(4).存儲過程能過減小網絡流量。當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,大大增長了網絡流量並下降了網絡負載。oop

(5).存儲過程可被做爲一種安全機制來充分利用。系統管理員經過執行某一存儲過程的權限進行限制,可以實現對相應的數據的訪問權限的限制,避免了非受權用戶對數據的訪問,保證了數據的安全。優化

 

 

二、
 存儲過程procedure
  變量:

  全局變量:以@開頭,如@var1,設置方法爲set @var1 = 1000;select @var1 := 'hello,test!';

 

         mysql> set @a=100;

                 mysql> select @a;

                 msyql>select  count(*) into @var1 from employees;

         mysql>select @var1;

  系統變量:
  系統變量使用@@引用
  
  局部變量:
  局部變量用在begin...end語句中,聲明的是局部變量
  delare var1 int;
  set var1=100;
  
  例:存儲過程示例
  mysql> create procedure sp1()
    -> begin
    -> declare var1 int;
    -> declare var2 int default 0;
    -> declare var3 varchar(20) charset utf8 default '湖南工業大學';
    -> set var1=10000;
    -> set var2=111;
    -> select var1,var2,var2;
    -> end

    -> //

msyql> delimiter ;

mysql> call sp1();  

 


 一、使用存儲過程傳遞參數
    in    傳入參數
    out   傳出參數
    inout 傳入傳出參數
    
    例:使用存儲過程統計指定表的記錄數,而且記錄數能在外面使用
    mysql> create procedure sp2(out num int)
    -> begin
    -> select count(*) into num from employees;
    -> end

    -> //

    mysql>call sp2(@num)

   mysql>select @num;

    
    例:使用存儲過程建立users表,包含id,name和sex三個字段
    mysql> create procedure sp3(id int,name varchar(20),sex enum('man','woman'))
    -> begin
    -> create table if not exists users
    -> (
    -> id int primary key,
    -> name varchar(20),
    -> sex enum('man','woman')
    -> )engine=innodb charset=utf8;
    -> insert into users values(id,name,sex);
    -> select * from users;
    -> end

    -> //

mysql> call sp3(1,'松江','man');

    

 傳入傳出參數:
    mysql> create procedure sp4(inout va int)
    -> begin
    -> set va := va + 10;
    -> set va=va+10;
    -> select va+10 into va;       va是形參
    -> end
    -> //
    
    mysql> set @var1=100;
    mysql> call sp4(@var1);       var1是實參
    mysql> select @var1;

 


  存值方法:
    select .... into var|@var
    select @var := 100
    select emp_no,first_name into var1,var2(必須使用declare進行聲明)
    select emp_no,first_name into @var1,@var2
    select @var1 := emp_no,@var2 := first_name from employees
    
    

聲明變量

declare num1,num2 int,name varchar(20)

 

 

============================

 

                             第11章存儲過程
1、基本語法 create procedure sp_name([proc_parameter[,...]])
[characteristic...]routine_body 
begin
end
sp_name 表示存儲過程的名字
proc_parameter 存儲過程參數例表[IN OUT INOUT]三個部分組成
其中IN 表示傳進來的參數
其中OUT 表示傳出去的參數
其中INOUT 表示傳進來但最終傳回的參數
routine_body 參數是SQL代碼的內容(相似於觸發器的for each row)
begin..end標誌SQL代碼的開始和結束



2、關於IN OUT INOUT的舉例說明
(1)IN 參數例子
delimiter &&
create procedure alvin1(in p_in int) #設置傳入的參數類型和變量
begin
select p_in;  #查詢第一次傳入的參數值
set p_in=2;   #內部從新賦值給p_in變量
select p_in;  #賦值後在此查詢
end &&
delimiter ;
set @p_in=5;  #開始傳入參數1
call alvin1(@p_in); #調用存儲過程,查看和對比輸出的值



(2)
OUT 參數例子
delimiter &&
create procedure alvin2(out p_out int)
begin
select p_out;
set p_out=2;
select p_out;
end &&
delimiter ;
set @p_out=5; 傳入的參數1以後
call alvin2(@p_out);
調用了以後。是否和IN同樣都顯示出來了?仍是無效? 不和IN同樣,不能傳參


(3)
INOUT 參數例子
delimiter &&
create procedure alvin3(inout p_inout int)
begin
select p_inout;
set p_inout=2;
select p_inout;
end &&
delimiter ;
set @p_inout=5;
call alvin3(@p_inout);
 
和IN的結果同樣


 3、舉例說明
需求一:建立一個存儲過程,要求(返回mysql的版本,用戶 所在的數據庫、用戶名稱)
delimiter &&
create procedure zy1(
out getversion varchar(30),
out userversion varchar(30),
out userdatabase varchar(30),
out userconnection int)
reads sql data
begin
select version() into getversion;
select user() into userversion;
select database() into userdatabase;
select connection_id() into userconnection;
end &&
delimiter ;
>call zy1(@a,@b,@c,@d);
>select @a,@b,@c,@d;



需求2、統計vendors vend_id的數量總共有多少條?
out zycount int
select count(*) into zycount from vendors
    
  
  delimiter &&
  create procedure vend_idnum(out vend_num int)
  begin
  select count(*)  into vend_num from vendors;
  end &&
  delimiter ;
  
  call vend_idnum(@idnum);
  select @idnum;

 #==============  流程控制  ======================
                     
(1)存儲過程if語句的使用方法
delimiter &&
create procedure zyif(in aa int,out bb int)
begin
if aa>20 then set bb=30;
elseif aa=20 then set bb=20;
else set bb=15;
end if;
end &&
delimiter ;
call zyif(50,@bb);
select @bb;

 (2)存儲過程case用法
語法: case 操做數
         when 條件 then 執行語句;
         when 條件 then 執行語句;
         when 條件 then 執行語句;
         else 執行語句
       end case
例:
 mysql> delimiter &&
mysql> create procedure zy_case(in aa int,inout bb int)
    -> begin
    -> case
    -> when aa=20 then set bb=20;
    -> when aa>20 and aa<=50 then set bb=30;
    -> when aa>51 then set bb=60;
    -> else set bb=15;
    -> end case;
    -> end &&
    -> delimiter ;

mysql> call zy_case(60,@bb);
mysql> select @bb;

例:使用存儲過程添加學生,當學生的id除3,餘0時將學生插入s01班,餘1時插入c02班,餘2時插入c03班,
每一個班的字段爲id,name,age,sex四個字段。
mysql> create table c01(id int primary key,name varchar(10) not null,age int,sex enum('woman','man'));
mysql> create table c02 select from c01 where 1=2;//複製表結構。
mysql> delimiter //
mysql> create procedure sp6(in id int,in name varchar(10),in age int,in sex enum('woman','man'))
    -> begin
    -> declare num int;
    -> set num=mod(id,3);
    -> case num
    -> when 0 then insert into c01 values(id,name,age,sex); 
    -> when 1 then insert into c02 values(id,name,age,sex);
    -> when 2 then insert into c03 values(id,name,age,sex);
    -> else 
    -> insert into c01 values(id,name,age,sex);
    -> end case;
    -> end
    -> //
mysql> delimiter ;
mysql> call sp6(2,'林黛玉','20','woman');


select case age
when 20 then 語句;
when 30 then 語句;
...
else
語句;
end case from 表名;

select case
when age >= 20 && age<= 25 then 語句;
when age >25 && age<=60 then 語句;
...
else
語句;
end case from 表名;


 


(3)while 循環使用,插入1萬數據
建立一個表
create table zybb(
user_id int,
name varchar(10));
Query OK, 0 rows affected (0.10 sec)

delimiter &&
create procedure zy_while()
begin
declare count int default 0;
while count < 100000 do
insert into zybb(user_id,name)values(count,'aaa1');
set count=count + 1;
end while;
end &&
delimiter ;
call zy_while(); 調用存儲過程

(3)while 循環
  leave  跳出循環
  iterate 跳過本次循環
語法: while  [expression] do
   statements
  end while
  例:使用存儲過程計算指定數字從1開始的和值
     mysql> delimiter //
     mysql> create procedure sp3(in snum int)
         -> begin
         -> declare sum,i int;
         -> set sum=0,i=0;
         -> sxjy:while  i <= snum  do
         -> set sum := sum + i;
         -> set i := i + 1;
         -> end while;
         -> select sum;
         -> end
         -> //
    mysql> delimiter ;

練習:在test數據庫下新建test1表,包括 
       id (整型,主鍵),
       num1 (整型,從1到200的隨機數),
       dt  (datetime類型,爲當前系統日期時間)
   而後使用while循環插入200條記錄。
    mysql> create table test1(id int primary key auto_increment,num1 int,dt datetime);
    msyql> delimiter //
    mysql> create procedure test_while(in num int)
        -> begin
        -> declare num int default 1;
        -> sxjy:while  num <= 200 do
        -> insert into test1(num1,dt) values(rand()*200,now());
        -> set num := num + 1;
        -> end while;
        -> select * from test1;
        -> truncate test1;
        -> end
        -> //
  mysql> delimiter ;


 (4)loop 循環(無限循環)
 label:loop
    statements
    if 退出條件
        leave label;
    end if; 
  end loop
   例:使用存儲過程計算指定數字從1開始的和值
       msyql> delimiter //
       mysql> create procedure sp4(in snum int)
           -> begin
           -> declare sum,i int;
           -> set sum=0,i=0;   
           -> if i<= snum then
           -> set sum := sum + i;
           -> set i := i+ 1;
           -> else
           -> leave sxjy;
           -> end loop;
           -> select sum;
           -> end;
           -> //
     mysql> delimiter ;

(5)repeat until 循環
 語法: repeat
         循環體
        until 條件
        end repeat;
   mysql> create procedure sp6( in snum int)
       -> begin
       -> declare sum,i int;
       -> set sum=0,i=0;
       -> repeat
       -> set sum := sum + 1;
       -> set i := i + 1;
       -> until i > snum
       -> end repeat;
       -> select sum;
       -> end
       -> //


#===========================================================
(1)調用存儲過程
call+存儲過程名稱+參數
如:call alvin_name(@p_inout)

(2)查詢結果
select @p_inout

(3)查詢存儲過程
show procedure status\G;

(4)查詢某個存儲過程詳細
show create procedure alvin1\G;

(5)查詢存儲函數
show function status\G;

(6)查詢某個詳細的存儲函數
show create function alvin10\G;

(7)刪除存儲過程
drop procedure alvin1;

(8)刪除存儲函數
drop function alvin1;

#=========  存儲函數  ==================

 

 create function sp_name([func_parameter[,.....]]) 

return type [characteristic...] routine_body

 begin...end 

其中sp_name 存儲函數的名稱

 func_parameter 函數參數列表

 return type 指定返回的參數類型
 routine_body SQL代碼內容

begin..end標誌SQL代碼的開始和結束 


注意:與存儲過程不一樣, 一、參數只有輸入類型 二、向調用方返回結果值

 

 舉例: 

delimiter &&
 create function alvin11(bb_id int)

returns varchar(20) 

begin 

return(select vend_name from vendors where vend_id=bb_id); 

end && 

delimiter ; 

select  alvin11(1002); 

 

 練習:編寫一個存儲函數,要求出入cust_id的的時候返回order_date這個字段的值 表名爲:orders 
delimiter &&

create function alvin33(aa_id int)

 returns datetime

 begin

 return(select order_date from orders where cust_id=aa_id); 

end && 

delimiter ; 
select alvin33(10003);

 

 

  ====================  本章練習題目 =============

一、編寫一個存儲過程要求全自動填充 gongda 表,用戶輸入0,那麼就填充數據爲10萬條。gongda結構包含

user_id user_name local_time字段。數據類型分別int varchar time

 

二、編寫一個存儲過程將gongda表前5000條 的local_time 用now()函數批量填上時間。

 

三、編寫一個存儲過程,用戶輸入大於1000時,返回值爲1001 ,用戶輸入小於1000時或者大於等於800時返回值爲999 其它的返回值爲1;

 

四、編寫一個存儲函數,根據gongda表 用戶輸入的user_id號返回user_name和local_time。

五、vendors表,有3個參數,

user_id 和type  info

若是type的值爲1,將vend_name傳給輸出參數info 根據存儲過程user_id查詢vendors表中的記錄,

若是type的值爲2  將地址給輸出參數info,根據存儲過程user_id查詢vendors表中的記錄,

 

 

六、orders表中,有兩個參數,user_id和type

根據user_id 用來查詢orders表中的信息,

type類型的值若是爲1,則返回訂單日期,若是爲2則返回訂單編號。

若是爲其它則返回錯誤。

 

 

 

 

============== 答案分析 =======

1.
mysql> qdelimiter &&

mysql> create procedure gongda_while()

    -> begin
       -> declare count int default 0;
       -> while count<10000
      -> do
      -> insert into gongda(user_id,user_name,local_time) values(count,'zhang',now());
      -> set count=count + 1;
      -> end while; 
      -> update gongda set local_time=null where user_id<=5000;
     -> end &&
 mysql> delimiter ;
mysql> call gongda_while();

mysql> select * from gongda;

 

 

3.
  
mysql> delimiter &&

mysql> create procedure zll_if(in num int,out bb int)
      -> begin
     -> if num>1000 then set bb=1001;
     -> elseif num<1000  and num>=800 then set bb=999;
     -> else set bb=1;
     -> end if;
     -> end &&
     -> delimiter ;
mysql> call zll_if(60,@bb);
mysql> select @bb; 
4.

mysql> delimiter &&
mysql> create function zll(
       -> bb_id int,return1 varchar(20),return2 varchar(20))
       -> returns varchar(100)
       -> begin
       -> select user_name into return1 from gongda where user_id=bb_id;
       -> select local_time into return2 from gongda where user_id=bb_id;
       -> return concat(return1,":",return2);
       -> end &&
 mysql> delimiter ;


5.

mysql> delimiter &&
mysql> create procedure vendors_if(in type int,in user_id int,out info varchar(30))
       -> begin
       -> if  type=1  then   select vend_name into info from vendors where vend_id=user_id;
       -> elseif type=2 then   select vend_address into info from vendors where vend_id=user_id;
       -> end if;
       -> end &&
       -> delimiter ;
mysql> call vendors_if(1,1002,@info);
mysql> select @info;

 
6.

mysql> delimiter &&
mysql> create procedure orders_if(in user_id int,in type int,out info varchar(20))
       -> begin
       -> if type=1 then select order_date into info from orders where cust_id=user_id;
       -> elseif type=2 then select order_num  into info from orders where cust_id=user_id;
       -> end if;
       -> end &&
       -> delimiter ;
mysql> call orders_if(10003,1,@info);
mysql> select @info;

相關文章
相關標籤/搜索