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$