一、快速了解什么是存储过程和函数?
存储过程和函数是事先经过编译并存储在数据库中的一段 SQL 语句的集合,调用存储过程
和函数可以简化应用开发人员的很多工作,减少数据在数据库和应用服务器之间的传输,对
于提高数据处理的效率是有好处的。
在对存储过程或函数进行操作时,需要首先确认用户是否具有相应的权限。例如,创建存储过程或者函数需要 CREATE ROUTINE 权限,修改或者删除存储过程或者函数需要 ALTER
ROUTINE 权限,执行存储过程或者函数需要 EXECUTE 权限。
存储过程和函数的区别在于函数必须有返回值,而存储过程没有,存储过程的参数可以使用IN、OUT、INOUT 类型,而函数的参数只能是 IN 类型的。
二、语法(MySQL8.0官方语法)
在对存储过程或函数进行操作时,需要首先确认用户是否具有相应的权限。例如,创建存储过程或者函数需要 CREATE ROUTINE 权限,修改或者删除存储过程或者函数需要 ALTER
ROUTINE 权限,执行存储过程或者函数需要 EXECUTE 权限。
1. 创建、修改存储过程或者函数
-- 创建
CREATE
[DEFINER = { user | CURRENT_USER }]
PROCEDURE sp_name ([proc_parameter[,...]])
[characteristic ...] routine_body
CREATE
[DEFINER = { user | CURRENT_USER }]
FUNCTION sp_name ([func_parameter[,...]])
RETURNS type
[characteristic ...] routine_body
proc_parameter:
[ IN | OUT | INOUT ] param_name type
func_parameter:
param_name type
type:
Any valid MySQL data type
characteristic:
COMMENT 'string'
| LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
routine_body:
Valid SQL routine statement
-- 修改
ALTER {PROCEDURE|FUNCTION] proc_name [characteristic ...]
characteristic:
COMMENT 'string'
| LANGUAGE SQL
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
2.删除存储过程或者函数
DROP {PROCEDURE | FUNCTION} [IF EXISTS] sp_name
3.查看存储过程或者函数
-- 查看状态
SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']
-- 查看定义
SHOW CREATE {PROCEDURE | FUNCTION} sp_name
-- 通过查看 information_schema. Routines 了解存储过程和函数的信息
select * from routines where ROUTINE_NAME = sp_name \G
4.调用存储过程或者函数
--调用存储过程
CALL sp_name([parameter[,...]])
--调用函数
SELECT sp_name([parameter[,...]])
三、变量的使用、流程控制语句和光标的使用
在使用存储过程或者函数之前我们要学会使用变量和流程控语句的使用,因为这是业务逻辑中重要的组成部分。我们可以通过 DECLARE 可以定义一个局部变量,变量的定义必须写在复合语句的开头,并且在任何其他语句的前面。可以一次声明多个相同类型的变量。如果需要,可以使用 DEFAULT 赋默认值。也可以通过set为变量赋值。可以使用 IF、CASE、LOOP、LEAVE、ITERATE、REPEAT 及 WHILE 语句进行流程的控制
变量的分类
-
局部变量: 使用在存储过程或函数中,这样的变量使用 declare 进行声明,使用 set 进行赋值。作用域是过程中。
--语法 DECLARE var_name[,...] type [DEFAULT value] SET var_name = expr [, var_name = expr] ... --案例 -- 定义变量并赋予初始值 declare num int default 0; -- 给变量赋值 set num=100;
-
用户变量: 用户根据自己的需求进行定义的变量,只存在当前回话中,需要用 @ 符号进行修饰。
-- 创建 set @num = 666; select @num :=666;
-
系统变量: 系统自带的,内建的变量
可以通过命令行的方式进行设置,如:mysqld –default_storage_engine=MyISAM
可以在 my.ini 配置文件中进行配置,如:default_storage_engine=MyISAM
可以通过 set 的方式进行动态设置
系统变量,分为两类:
-- 全局的(global) show global variables; set global default_storage_engine=MyISAM; set @@global.default_storage_engine=MyISAM; -- 会话的(session) -- 查看全局变量的方法 show session variables; show local variables; show variables; -- 设置全局变量的写法 set session default_storage_engine=MyISAM; set local default_storage_engine=MyISAM; set @@session.default_storage_engine=MyISAM; set @@local.default_storage_engine=MyISAM; set default_storage_engine=MyISAM; set @@default_storage_engine=MyISAM;
流程控制语句
1.IF 语句
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF
2.case 语句
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
or:
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE
3.loop循环(leave退出循环,iterate跳过循环,二者适用所有的循环)
[label:] LOOP
statement_list
-- 如果满足条件退出循环
-- 如果没有loop没有配合leave使用,将会形成死循环
IF search_condition THEN statement_list
leave [label];--跳出循环
-- 跳过循环
-- iterate [label];
END IF;
END LOOP [label]
4.repeat语句
REPEAT
statement_list
UNTIL search_condition END REPEAT
5.while语句
WHILE search_condition DO
statement_list
END WHILE
光标的使用
在存储过程和函数中可以使用光标对结果集进行循环的处理。光标的使用包括光标的声明、
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
四、案例集合
注意:在命令行窗口创建函数或者存储过程之前,要改变一下结束符";",使用delimiter关键字进行改变,创建完毕后再改变过来。
1. 没有参数,只含有返回值的自定义函数
-- 更改结束符
delimiter //
-- 如果函数存在就删除
drop function if exits fun_randid;
-- 创建函数
create function fun_randid() returns varchar(100)
begin
return UUID();
end
//
--函数创建结束
-- 更改结束符
delimter ;
-- 函数的调用
select fun_randid();
2. in类型参数的自定义函数
delimiter //
drop function if exits fun_randid;
create function fun_randid(size int) returns varchar(100)
begin
return substring(UUID(),0,size);
end//
delimter ;
-- 调用
select fun_randid(10);
3.没有参数的存储过程
delimiter //
drop procedure if exits proc_select_data;
create procedure proc_select_data())
begin
select * from book_info limit 10;
end//
delimter ;
-- 调用
call proc_select_data
4.in类型参数的的存储过程
delimiter //
drop procedure if exits proc_insert_data;
create procedure proc_insert_data(in name varchar(25)) -- in可以省略
begin
insert into book_info(book_name) values(name);
end//
delimter ;
-- 调用
call proce_insertdata('MySQL从入门到精通');
5.out类型参数的存储过程
delimiter //
drop procedure if exits proc_count_book;
create procedure proc_count_book(out count int)
begin
select count(*) into count from book_info;
end//
delimter ;
--调用
call proce_count_book(@count);
select @count;
6.inout类型参数的存储过程
delimiter //
drop procedure if exits proc_insert_count;
create procedure proc_insert_count(inout data varchar(25))
begin
-- 拿到参数插入表中
insert into book_info(book_name) values(data);
-- 设置参数的值
select count(*) into data from book_info;
end//
delimter ;
--调用
set @data = 'MySQL性能调优'; -- 设置传入参数的值
call proc_insert_count(@data); -- 调用存储过程
select @data; -- 得到输出参数的值
7.综合应用——使用光标循环结果集的存储过程
delimiter //
drop procedure if exits proc_concat_string;
create procedure proc_concat_string(out str text)
begin
declare count int;
declare str_concat text default '';
-- 注意游标的定义一定要在所有的自定义的变量后面,否则会报错,错误编号1337
-- 1.定义游标
declare c_name cursor for select rand_string from rand limit 10;
-- 2.捕获异常,如果捕捉到了将count设置为1
declare continue handler for not found set count = 1;
set str = '';-- 设置输出参数初始值
-- 3.打开游标
open c_name;
point:loop
-- 4.使用游标
fetch c_name into str_concat;
set str = concat(str,str_concat);
-- 5.设置退出循环
if count = 1 then
leave point;
end if;
end loop;
-- 6.关闭游标
close c_name;
end//
delimiter ;
-- 调用
set @str='';
call proc_concat_string(@str);
select @str;
8.综合应用——自定义函数生成随机字符串
delimiter //
drop function if exits fun_randString;
-- 两个参数:生成的随机字符串的长度和字符串类型(1:字符;2:数字;其他:字符数字混合)
create function fun_randString(size int,type int) returns varchar(255)
BEGIN
declare chars varchar(26) default 'qwertyuiopasdfghjklzxcvbnm';
declare num varchar(10) default '1234567890';
declare string varchar(255) default '';
declare rand_string varchar(255) default '';
declare count int default 0;
set string = case type
when 1 then chars
when 2 then num
else concat(chars,num)
end;
while count<size do
set rand_string = concat(rand_string,substring(string,floor(1+rand()*length(string)), 1));
set count = count + 1;
end while;
-- REPEAT
-- set rand_string = concat(rand_string,substring(string,floor(1+rand()*length(string)),1));
-- set count = count + 1;
-- until count>=size end repeat;
return rand_string;
END//
delimiter ;
-- 调用
select fun_randString(10, 2);