MySQL存储过程和存储函数详细使用教程

开始之前

首先创建如下两张表,并初始化一些数据。

MySQL存储过程和存储函数详细使用教程_第1张图片

MySQL存储过程和存储函数详细使用教程_第2张图片

创建存储过程(CREATE PROCEDURE)

基本语法格式如下:

CREATE PROCEDURE sp_name (parameters)
[characteristics ...] routine_body

其中:CREATE PROCEDURE为创建存储过程的关键字;sp_name为存储过程的名称(唯一性,没有所谓的重载方法概念);parameters为参数列表;characteristics指定存储过程的特性(该部分可以省略,即使用默认声明);routine_body是SQL代码的内容,可以用BEGIN...END来表示SQL代码的开始和结束。

parameters 表现形式 --> [IN(OUT/INOUT)] param_name type。IN代表入参、OUT代表出参、INOUT代表既可以是入参也可以是出参, param_name参数名称,type是类型(类型是mysql数据库中支持的任意类型,VARCHAR需要指定长度,如VARCHAR(255))。

characteristics 表现形式 --> 

名称 说明
LANGUAGE SQL 说明routine_body部分是由SQL语句组成的,当前系统支持的语言为SQL,SQL是LANGUAGE特性的唯一值
[NOT] DETERMINISTIC 指明存储过程执行的结果是否确定。DETERMINISTIC表示结果是确定的。每次执行存储过程时,相同的输入会得到相同的输出。NOT DETERMINISTIC表示结果是不确定的,相同的输入可能得到不同的输出。如果没有指定任意一个值,默认为 NOT DETERMINISTIC
{CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA} 指明子程序使用SQL语句的限制。CONTAINS SQL表明子程序包含SQL语句,但是不包含读写数据的语句;NO SQL表明子程序不包含SQL语句;READS SQL DATA说明子程序包含读写读数据的SQL语句;MODIFIES SQL DATA表明子程序包含写数据的语句;默认情况下,系统会指定为CONTAINS SQL。
SQL SECURITY {DEFINER | INVOKER} 指明谁有权限来执行。DEFINER表示只有定义者才能执行。INVOKER表示拥有权限的调用者可以执行。默认情况下,系统指定为DEFINER
COMMENT 'string' 注释信息,可以用来描述存储过程或存储函数。

--简单的示例

DELIMITER $$  -- 声明结束符
CREATE PROCEDURE list_emp() -- 创建无参数存储过程
	COMMENT '查询所有员工及其所在部门' -- characteristics 部分(可以省略)
	BEGIN
		SELECT * FROM tb_emp e
		INNER JOIN tb_dept d
		ON e.dept_id = d.dept_id;
	END $$
DELIMITER ; -- 恢复默认结束符

CALL list_emp(); -- 调用存储过程

SHOW PROCEDURE STATUS LIKE '%list_emp%'; -- 查看存储过程

DROP PROCEDURE list_emp;  -- 删除存储过程,目前编写错误的话直接删除重写

存储过程定义详情(SHOW PROCEDURE STATUS LIKE '%list_emp%'; -- 查看存储过程):

执行结果(CALL list_emp(); -- 调用存储过程):

MySQL存储过程和存储函数详细使用教程_第3张图片

--有参数的存储过程

DELIMITER $$
CREATE PROCEDURE count_emp(OUT total_emp INT)
	COMMENT '统计员工数量'
	BEGIN
		SELECT COUNT(*) INTO total_emp FROM tb_emp;
	END $$
DELIMITER ;

SET @total_emp = 10; -- 声明变量

CALL count_emp(@total_emp); -- 调用存储过程

SELECT @total_emp; -- 获取结果

DROP PROCEDURE count_emp; -- 删除存储过程

执行结果:

总结说明

1、这里的'DELIMITER $$'语句的作用是将mysql的结束符号设置为'$$',因为mysql默认的结束符号是';',为了避免与存储过程中的SQL语句结束符号冲突,需要使用'DELIMITER'改变存储过程的结束符,并以'END $$'结束存储过程。存储过程定义完毕再以'DELIMITER ;'恢复默认结束符号。亦可以指定其它符号为结束符,但是不能用反斜杠'\',它是mysql中的转义符。当然,简单的存储过程不更改结束符大多数情况下也是不会出现错误的。

2、有参数的时候,VARCHAR类型需要指定长度,比如VARCHAR(255)。

创建存储函数(CREATE FUNCTION)

基本语法格式如下:

CREATE FUNCTION func_name(params)
RETURNS type
[characteristics ...] routine_body

其中:CREATE FUNCTION为创建存储函数的关键字;func_name为存储函数的名称(唯一性,没有所谓的重载方法概念);params为参数列表;RETURNS type语句表示函数返回数据的类型,可以是mysql中的任意数据类型;characteristics指定存储函数的特性(和存储过程一样);routine_body是存储函数主体。

参数列表:IN、OUT、或INOUT只对PROCEDURE是合法的(FUNCTION中总是默认IN参数,所以声明存储函数入参的时候不不能声明IN,会报错,因为默认是IN)。RETURNS子句只能对FUNCTION作指定,对函数而言这是强制的。它用来指定函数的返回类型,而且函数体必须包含一个RETURN value语句。

-- 简单的示例:

DELIMITER $$ -- 更改结束符
CREATE FUNCTION count_dept()
	RETURNS INT
	COMMENT '统计部门数量'
	BEGIN
		RETURN (SELECT COUNT(*) FROM tb_dept);
	END $$
DELIMITER ; -- 还原结束符

DROP FUNCTION count_dept; -- 删除存储函数

SHOW FUNCTION STATUS LIKE '%count_dept%';  -- 查看存储函数定义

SELECT count_dept();  -- 调用存储函数

执行结果(SELECT count_dept();  -- 调用存储函数):

变量的使用(关键字:DECLARE)

变量可以在子程序中声明并使用,这些变量的作用域范围是在BEGIN...END程序中,不能单独在存储过程外部声明变量

1、定义变量

基本语法:

DECLARE var_name[,var_name1]... date_type [DEFAULT value];

var_name是局部变量的名称,可以同时声明多个变量,但是类型只能声明一次,就是说声明多个变量只能是同类型;date_type是变量类型,可以是mysql中任意的数据类型(VARCHAR需要指明长度,例如VARCHAR(255));DEFAULT 为变量设置默认值,如果是多参数,不能使用,默认值可以被声明为常量,也可以指定一个表达式。如果没有指定默认值,则为null

简单的示例:

DECLARE param1 INT DEFAULT 10; -- 声明单参数

DECLARE param1, param2, param3 INT; -- 声明多参数

2、为变量赋值

定义变量后,可以为变量赋值以改变其值。

通过SET...为变量赋值,基本语法:

SET var_name = expr[,var_name=wxpr]....; -- 可以同时为单个或多个变量赋值,expr可以是具体的值,也可以是表达式。

--简单的示例

DECLARE param1, param2, param3 INT; -- 声明3个变量
SET param1=10, param2=20; -- 为param1和param2赋具体的值
SET param3 = param1 + param2; -- 将param1和param2的运算结果赋值给param3

通过SELECT...INTO...为一个或多个变量赋值,基本语法如下:

SELECT col_name[,...] INTO var_name[,...] table_expr;

这个SELECT语法把选定的列直接存储到对应位置的变量(所以要求col_name和var_name一一对应)。col_name表示字段名称,var_name表示定义的变量名称;table_expr表示查询条件表达式,包括名称和WHERE子句。

--简单的示例:

SELECT dept_name, dept_addr INTO v_dept_name, v_dept_addr FROM tb_dept WHERE dept_id = 1;

事务的使用

事务并不会影响存储过程或存储函数的执行顺序,也不会中断执行(存储过程或存储函数始终会执行到END)。

START TRANSACTION; -- 开始事务

COMMIT; -- 提交事务

ROLLBACK; -- 回滚事务

流程控制的使用

流程控制语句用来根据条件,控制语句的执行。mysql中用来构造控制流程的语句有:IF、CASE、LOOP、LEAVE、ITERATE、REPEAT、WHILE。

IF语句(说明:mysql中还有一个IF()函数,注意区别):

注意:IF语句必须配合THEN、END IF使用。除了IF还有ELSEIF(没有分开)和ELSE。

基本语法:

IF (expr_condition) THEN
	....do something.....
ELSEIF (expr_condition) THEN
	....do something.....
ELSE
	....do something.....
END IF;

说明:如果表达式expr_condition计算结果为true,则执行THEN后面的逻辑,如果都不匹配则执行ELSE。条件判断表达式建议用括号包起来,增加可读性。

CASE语句

CASE语句也是一个条件判断语句。需要配合WHEN、THEN和END CASE使用

CASE语句有两种语法格式:

CASE
	WHEN expr_condition THEN ...do something...
	WHEN expr_condition THEN ...do something...
	....多个 WHEN THEN 语句.....
        [ELSE ...do something...]
END CASE;

其中expr_condition为条件表达式,计算结果为true,则执行THEN后面的语句。多个WHEN...THEN依次执行,ELSE为可选条件。

另外一种语法格式:

CASE case_expr
	WHEN expr THEN .....do something....
	WHEN expr THEN .....do something...
	....多个表达式...
	[ELSE ...dosomething..]
END CASE;

其中,case_expr表示条件判断的表达式,WHEN后的表达式结果如果和case_expr匹配,则执行相应的THEN后面的语句。没有则执行ELSE,ELSE为可选。这种语法类似switch...case(建议使用第一种,逻辑清晰一点)。

LOOP、REPEAT、WHILE、LEAVE和ITERATE

其中LOOP、REPEAT和WHILE都是创建循环语句的关键词。

LEAVE用来退出任何被标注的循环语句(类似break,只能用于循环语句)。

ITERATE语句将执行顺序转到语句段开头处(类似continue,只能用于循环语句)。

LOOP基本语法(需要配合 END LOOP):

[loop_label]:LOOP
	...do something....
END LOOP [loop_label];

其中,loop_label为可选,表示LOOP体的标签,do something为循环体。

LOOP简单示例(配合LEAVE和ITERATE):

DECLARE id INT DEFAULT 0;
add_loop:LOOP
	SET id = id + 1;
	IF(id>10) THEN
		LEAVE add_loop;
	ELSE
		ITERATE add_loop;
	END IF;
END LOOP add_loop;

REPEAT基本语法(需要配合 UNTIL和END REPEAT):

[repeat_label:] REPEAT
	....do something....
UNTIL expr_condition;
END REPEAT [repeat_label];

其中,repeat_label为可选,表示REPEAT循环语句的标签,UNTIL指定循环条件。REPEAT执行过程是,每次循环体执行完毕需要去判断一下条件表达式expr_condition,如果为true继续执行,否则结束循环。

WHILE基本语法(需要配合DO和END WHILE使用):

[while_lebel:] WHILE expr_condition DO
	.....do something....
END WHILE [while_label];

其中,while_label为可选,表示WHILE循环语句的标签。WHILE的执行过程是,先判断条件表达式expr_condition,如果为true执行循环,否则结束循环(与REPEAT的区别是:WHILE先判断条件,REPEAT是后判断条件)。

调用存储过程

基本语法:

CALL sp_name([params,...]);

说明:如果存储过程没有参数,不能省略括号;参数个数要与存储过程定义的入参和出参个数匹配,用逗号隔开;出参类型的参数需要加上@符号。

调用存储函数

基本语法:

SELECT func_name([params...]);

说明:如果存储函数没有参数,不能省略括号;因为存储函数都是入参,所以只需注意匹配个数即可。

查看存储过程和存储函数

基本语法:

SHOW [PROCEDURE | FUNCTION] STATUS [LIKE 'pattern'];

说明:查看存储过程即PROCEDURE、存储函数即FUNCTION。LIKE为过滤条件(按存储过程、函数名字匹配),如果没有则是查看所有定义。

SHOW [CREATE | PROCEDURE] FUNCTION sp_name;

此语句查看定义存储函数、存储过程的脚本。

删除存储过程、存储函数

基本语法:

DROP [PROCEDURE | FUNCTION] [IF EXISTS] sp_name;

说明:sp_name为存储过程或存储函数的全称。[IF EXISTS]是mysql的一个扩展,建议使用。如果存储过程或函数不存在,它可以防止错误的产生,但是会产生一个用SHOW WARNINGS查看的警告。

修改存储过程、存储函数

注意:只能修改存储过程或函数的定义,不能修改执行的逻辑代码或参数

基本语法:

ALTER [PROCEDURE | FUNCTION] sp_name [characteristic.....];

其中,sp_name为存储过程或函数的名称,characteristic指定存储过程的特性。可以修改的特性和定义存储过程的时候的可选特性是一样的,不重复累赘


总结

1、存储过程和存储函数的区别(除了关键字:PROCEDURE、FUNCTION)

本质上都是存储程序。

参数类型不同:存储函数不允许声明出参类型,只能通过return关键字返回;

调用方式不同:存储过程用CALL,存储函数用SELECT;

存储函数限制比较多,多以建议使用存储过程,慎用存储函数。

2、修改存储过程、存储函数

存储过程或存储函数中的代码是不提供修改的,只能通过drop删除后,重新编写,或者直接编写一个新的程序。只能修改存储过程或存储函数的特性。

3、存储过程和存储函数可以相互调用

存储过程和存储函数包含自定义的SQL语句集合,所以,可以使用CALL或SELECT调用其它存储过程和存储函数。但是不能使用DROP删除其它存储过程和存储函数。

4、注意区别参数名字和表中的字段名

在定义存储过程和存储函数的时候,参数名称一定要与表中的字段名区别开来,否则可能出现无法预期的结果。

 

你可能感兴趣的:(MySQL)