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;