MySQL存储过程和存储函数

1.存储过程和存储函数

1.1.存储过程和函数概述

存储过程和函数是事先经过编译并存储在数据库中的一段SQL语句的集合,调用存储过程和函数可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对于提高数据的处理的效率是有好处的。

存储过程和函数的区别在于函数必须有返回值,而存储过程没有。

函数:是一个有返回值的过程;

过程:是一个没有返回值的函数;

1.2.创建存储过程

语法:

create procedure performance_name ([proc_parameter[....]])
begin
-- SQL语句
end;

示例:

delimiter $
create procedure pro_test1()
begin
    select 'Hello MySQL';
end$
delimiter ;

注意:
delimiter,该字段用来声明SQL语句的分隔符,告诉MySQL解释器,该段命令是否已经结束,mysql是否可以执行了
默认情况下,delimiter是分号;。在命令行客户端中,如果有一行命令以分号结束,那么回车后,mysql将会执行该命令。

1.3.调用存储过程

call procedure_name(); # procedure_name 存储过程的名字

1.4.查看存储过程

-- 查询db_name数据库中所有的存储过程
select name from mysql.proc where db = 'db_name';
-- 示例:select name from mysql.proc where db = 'mysql_senior';

-- 查询所有存储过程的状态信息
show procedure status;

-- 查询某个存储过程的定义
show create procedure mysql_senior.pro_test1;

1.5.删除存储过程

语法:

drop procedure [if exists] sp_name;

示例:

drop procedure pro_test1;

1.6.存储过程语法

存储过程是可以编程的,意味着可以使用变量,表达式,控制结构,来完成比较复杂的功能。

1.6.1.变量
  • DECLARE:

通过DECLARE可以定义一个局部变量,该变量的作用范围只能是在BEGIN…END块中。

语法:

DECLARE var_name[,...] type [DEFAULT value]

示例:

delimiter $
create procedure pro_test2()
begin
    declare num int default 5;
    select num+10;
end $
delimiter ;
  • SET

直接赋值使用SET,可以赋常量或者赋表达式

语法:

set var_name = expr [, var_name = expr] ...

示例:

delimiter $
create procedure pro_test3()
begin
 declare NAME varchar(20);
 set NAME = 'MYSQL';
 select NAME;
end $
delimiter ;

也可以通过select…into方式进行赋值操作

delimiter $
create procedure pro_test4()
begin
    declare countnum int;
    select count(*) into countnum from city;
    select countnum;
end $
1.6.2.if条件判断

语法

if search_condition then statement_list
    [elseif search_condition then statement_list] ...
    [else statement_list]
end if;

演示案例:

需求:根据定义的身高变量,判定当前身高的所属的身材类型
-- 180及以上 ------------> 身材高挑
-- 170-180  ------------> 标准身材
-- 170 以下  ------------> 一般身材
delimiter $
create procedure pro_test5()
begin
    declare height int default 175;
    declare message varchar(20);
    if height >= 180 then
        set message = '身材高挑';
    elseif height >= 170 and height < 180 then
        set message = '标准身材';
    elseif height < 170 then
        set message = '一般身材';
    end if;
    select message;
end$
delimiter ;
1.6.3.传递参数

语法

create procedure procedure_name([in|out|inout] 参数名 参数类型)
...

/*
in    :该参数可以作为输入,也就是需要调用方传入值,默认。
out   :该参数作为输出,也就是该参数可以作为返回值
inout :既可以作为输入参数,也可以作为输出参数
*/

IN-输入

演示案例:根据定义身高变量,判定当前身高的所属的身材类型

delimiter $
create procedure pro_test6(in height int)
begin
    declare message varchar(20);
    if height >= 180 then
        set message = '身材高挑';
    elseif height >= 170 and height < 180 then
        set message = '标准身材';
    elseif height < 170 then
        set message = '一般身材';
    end if;
    select concat('身高:',height,'对应的身材类型为:',message);
end $
delimiter ;

call pro_test6(175);

OUT-输出

演示案例:根据传入的身高变量,获取当前身高的所属的身材类型

delimiter $
create procedure pro_test7(in height int,out message varchar(20))
begin
    if height >= 180 then
        set message = '身材高挑';
    elseif height >= 170 and height < 180 then
        set message = '标准身材';
    elseif height < 170 then
        set  message = '一般身材';
    end if;
end $
delimiter ;

call pro_test7(175,@message);
select @message;

注意:

@message 这种变量要在变量名前面加上 @ 符号,叫做用户会话变量,代表整个会话过程它都是起作用的,这个类似于全局变量一样
@@global.sort_buffer_size:这种在变量前加上 @@ 符号叫做系统变量

INOUT-输入或输出

输入输出的使用也是差不多的

1.7.case结构

语法结构:

-- 方式一
case case_value
	when when_value then statemnet_list
	[when when_value then statement_list]...
	[else statement_list]
end case;

-- 方式二
case 
 when search_condition then statement_list
 [when search_condition then statement_list]
 [else statement_list]
end case;

演示案例: 给定一个月份,然后计算出所在的季度

delimiter $
create procedure pro_test8(month int)
begin
    declare result varchar(20);
    case
        when month >= 1 and month <= 3 then
        set result = '第一季度';
        when month >= 4 and month <= 6 then
        set result = '第二季度';
        when month >= 7 and month <= 9 then
        set result = '第三季度';
        when month >= 10 and month <= 12 then
        set result = '第四季度';
    end case;
    select concat('当前月份:',month,'对应的季节为:',result) as res;
end $
delimiter ;

call pro_test8(4);

1.8.while循环

语法结构:

while search_condition do
	statement_list
end while;

**演示案例:**计算从1加到n的值

delimiter $
create procedure pro_test9(n int)
begin
    declare total int default 1;
    declare num int default 1;
    while num <= n do
        set total = total+num;
        set num = num + 1;
    end while;
    select total;
end $
delimiter ;

call pro_test9(10);

1.9.repeat结构

有条件的循环控制语句,当满足条件的时候退出循环,while是满足条件才执行,repeat是满足条件就退出循环

语法:

repeat
    statement_list
    until search_condition
end repeat;

**演示案例:**从1加到n

delimiter $
create procedure pro_test10(n int)
begin
    declare total int default 1;
    repeat
    set total = total + n;
    set n = n - 1;
    until n = 0
    end repeat;
    select total;
end $
delimiter ;

call pro_test10(10);

1.10.Loop语句

loop实现简单的循环,退出循环的条件需要使用其他的语句定义,通常可以使用leave语句实现,具体语法如下

[begin_label:]loop
 statement_list
end loop[end_label]

如果不在statement_list中增加退出循环的语句,那么loop语句可以用来实现简单的死循环

1.11.leave语句

用来从标注的流程构造中退出,通常和begin…end或者循环一起使用。

使用loop和leave的实现退出循环的简单例子

delimiter $
create procedure pro_test11(n int)
begin
    declare total int default 0;
    ins:loop
        if n <= 0 then
            leave ins;
        end if;
        set total = total + n;
        set n = n - 1;
    end loop ins;
    select total;
end $
delimiter ;

call pro_test11(10);

1.12.游标/光标

游标是用来存储查询结果集的数据类型,在存储过程和函数中可以使用光标对结果集进行循环处理。
光标的使用包括光标声明:open、fetch和close,其语法分别如下

-- 声明光标
declare cursor_name cursor for select_statement;

-- open光标
open cursor_name;

-- fetch光标
fetch cursor_name into var_name[,var_name]...

-- close光标
close cursor_name;

示例:

-- 初始化脚本
create table emp(
 id int(11) not null auto_increment,
 name varchar(50) not null comment '姓名',
 age int(11) comment '年龄',
 salary int(11) comment '薪水',
 primary key (id)
) engine=innodb default charset =utf8;

insert into emp(id,name,age,salary) values (null,'金毛狮王',55,3800),(null,'白眉鹰王',60,4000),(null,'青翼蝠王',38,2800),(null,'紫衫龙王',42,1800);

-- 查询emp表中的数据,并逐行获取进行展示
delimiter $
create procedure pro_test12()
begin
 declare e_id int(11);
 declare e_name varchar(50);
 declare e_age int(11);
 declare e_salary int(11);
 declare emp_result cursor for select * from emp;

 open emp_result;

 fetch emp_result into e_id,e_name,e_age,e_salary;
 select concat('id=',e_id,',name=',e_name,',age=',e_age,',薪资为:',e_salary);

 fetch emp_result into e_id,e_name,e_age,e_salary;
 select concat('id=',e_id,',name=',e_name,',age=',e_age,',薪资为:',e_salary);

 fetch emp_result into e_id,e_name,e_age,e_salary;
 select concat('id=',e_id,',name=',e_name,',age=',e_age,',薪资为:',e_salary);

 fetch emp_result into e_id,e_name,e_age,e_salary;
 select concat('id=',e_id,',name=',e_name,',age=',e_age,',薪资为:',e_salary);

 fetch emp_result into e_id,e_name,e_age,e_salary;
 select concat('id=',e_id,',name=',e_name,',age=',e_age,',薪资为:',e_salary);

 close emp_result;
end$;
delimiter ;

call pro_test12();

# 通过循环结构,获取游标中的数据

delimiter $
create procedure pro_test13()
begin 
 declare id int(11);
 declare name varchar(50);
 declare age int(11);
 declare salary int(11);
 declare has_data int default 1;

 declare emp_result cursor for select * from emp;

 declare exit handler for not found select has_data = 0;

 open emp_result;
 repeat 
 fetch emp_result into id,name,age,salary;
 select concat('id=',id,',name=',name,',age=',age,',薪资为:',salary);
 until has_data = 0  end repeat;
 close emp_result;
end $
delimiter ;

call pro_test13();

1.13.存储函数

语法结构:

-- 语法
create function function_name([param type ...])
returns type
begin
    ...
end;

案例:定义一个存储函数,根据传入的条件返回city表中的总记录数

delimiter $
create function fun1(countryId int)
returns int
begin
    declare num int;
    select count(*) into num from city where country_id = countryId;
    return  num;
end $
delimiter ;

# 查看函数返回的结果
select fun1(1);

# 删除函数
drop function fun1;

你可能感兴趣的:(mysql,数据库,mysql)