delimiter

介绍函数和存储过程之前,需要先了解delimiter。

delimiter是mysql的sql命令分隔符(命令结束标识),出现分隔符表示命令已经结束了,mysql会执行分隔符之前的sql语句。
delimiter默认是分号;
如创建函数或存储过程时,中间有多个分号;,但并不希望mysql遇见分号就马上执行,这时就可以使用delimiter改变分隔符。
在函数创建完成后,再用delimiter还原成分号;
示例:

--输入一个名称,返回一个询问是否单身的字符串
drop function if exists `test_func`;
delimiter /
create function `test_func`(param varchar(20)) returns varchar(50) charset utf8 deterministic 
begin 
	return concat('hello',param,'! you are single dog?');
end
/
delimiter ;

--charset utf8:返回的字符串时utf8格式的。
--deterministic :指明存储过程或函数执行的结果是否正确。deterministic表示结果是确定的。每次执行存储过程或函数时,相同的输入会得到相同的输出。
--not deterministic表示结果是不确定的,相同的输入可能得到不同的输出。如果没有指定任意一个值,默认为not deterministic。
--concat函数支持一个或者多个参数,参数类型可以为字符串类型也可以是非字符串类型,对于非字符串类型的参数mysql将尝试将其转化为字符串类型,concat函数会将所有参数按照参数的顺序拼接成一个字符串做为返回值。

代码delimiter /表示将分隔符修改成/,你也可以修改成任意字符(或多个),只要你的函数或存储过程的代码中不会出现该字符即可。
如将delimiter /替换成:
delimiter #delimiter //delimiter ;;delimiter _end也是可以的。
千万别忘了在函数定义完成后还原回分号。

函数

函数不能返回表的结果集,如果需要返回表结果集请使用存储过程,或者存入临时表后查询临时表。函数中不支持事务操作,所以不要在函数中进行增删改操作。

基本结构:

create funciton 存储过程名称(参数名称 参数类型) returns 返回值类型
begin
    要执行的sql语句 ;
end;

代码示例

--修改指定id的用户名称,并返回受影响的行数。
drop function if exists test_func;
delimiter /
create function test_func(param1 int,param2 varchar(10))returns int
begin  
	update user set user_name=param_in2 where user_id=param_in1;
	return (select row_count());
end /
delimiter ;
--还有个和row_count的类似的found_rows,found_rows用来获取最后一次查询到行数

调用

select test_func(1,'李四');

存储过程

存储过程官方完整结构:

characteristic: 
    language sql 
  | [not] deterministic 
  | { contains sql | no sql | reads sql data | modifies sql data } 
  | sql security { definer | invoker } 
  | comment 'string' 
routine_body: 
    valid sql procedure statement or statements

基本结构

完整结构不明白没关系,大多数时候其实只用到基本结构。

create procedure 存储过程名称([in|out|inout] 参数名称 参数类型)
begin
    要执行的sql语句 ;
end;
--in输入,out输出,inout输入输出
--mysql存储过程参数如果不显式指定“in”、“out”、“inout”,则默认为“in”。

代码示例

--修改指定id的用户名称,并返回受影响的行数。
drop procedure if exists test_proc;
delimiter /
create procedure test_proc(in param_in1 int,IN param_in2 varchar(10), out param_out varchar(10))  
begin  
	update user set user_name=param_in2 where user_id=param_in1;
	set param_out=(select row_count());
end /
delimiter ;

另外也可以不通过输出参数来返回:

--返回全部用户以及所有姓王的用户
drop procedure if exists test_proc;
delimiter /
create procedure test_proc()  
begin
	select * from user;  
	select * from user where user_name like '王%';  
end /
delimiter ;

调用

declare result_varc varchar(10);
call test_proc(1,'李四',result_varc);

函数和存储过程的区别

语法结构不同,存储过程为了返回多个结果集,去掉的返回值,将返回值变成的输出out参数,而函数必须有返回值,只能接收输入参数。

功能定位不同,存储过程定义为操作特定表的一系列sql的集合,可以返回一个或多个结果集,而函数通常是不涉及特定用户表(有时候用来查询也是可以的),不能返回结果集,只能返回一个变量。

功能定位不同导致的,存储过程支持事务,函数不支持事务,函数中使用commit会报错:Error Code: 1422. Explicit or implicit commit is not allowed in stored function or trigger.。所以不要使用函数来增删改。

调用方式不同,存储过程一般是作为一个独立的执行语句,而函数可以作为查询语句的一个部分来调用。