存储函数
存储过程是一组为了完成某个特定功能的 SQL 语句集,其实质上就是一段存放在数据库中的代码,它可以由声明式的 SQL 语句(如 CREATE、UPDATE 和 SELECT 等语句)和过程式 SQL 语句(如IF-THEN-ELSE 控制结构语句)组成。这组语句集经过编译后会存储在数据库中,用户只需通过指定存储过程的名字并给定参数( 如果该存储过程带有参数),即可随时调用并执行它,而不必重新编译,因此这种通过定义一段程序存放在数据库中的方式,可加大数据库操作语句的执行效率。
一个存储过程是一个可编程的函数,同时可看作是在数据库编程中对面向对象方法的模拟,它允许控制数据的访问方式。因而,当希望在不同的应用程序或平台上执行相同的特定功能时。 存储过程尤为适合,其通常具有这样一些优点:
- 可增强 SQL 语言的功能和灵活性。存储过程可以用流控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。
- 良好的封装性。存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的 SQL 语句,并且数据库专业人员可以随时对存储过程进行修改,而不会影响到调用它的应用程序源代码。
- 高性能。存储过程执行一次后,其执行规划就驻留在高速缓冲存储器中,在以后的操作中。只需从高速缓冲存储器中调用已编译好的二进制代码执行即可,从而提高了系统性能。
- 可減少网络流量。由于存储过程是在服务器端运行,且执行速度快。那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而可降低网络负载。
- 存储过程可作为一种安全机制来确保效据库的安全性和数据的完整性。使用存储过可以完成所有数据库操作,并可通过编程方式控制这些数据库操作对数据库信息访问的权限。
创建存储过程
在 MySQL 5.5 中,可以使用 CREATE PROCEDURE 语句创建存储过程,其语法格式为:
sql
CREATE
PROCEDURE sp_name([ proc_parameter[,.])
[ characteristic... ] routine_body
其中,proc_parameter 的格式为:[ IN | OUT | INOUT ] param_name type
type 的格式为: Any valid MySQL data type
characteristic 的格式为:
sql
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
主要语法说明如下:
- sp_name:存储过程的名称,默认在当前数据库中创建。需要在特定数据库中创建存储过程时,则要在名称前面加上数据库的名称,即 db_name.sp_name 的格式。需要注意的是,这个名称应当尽量避免取与 MySQL 的内置函数相同的名称。否则会发生错误。
- proc_parameter:存储过程的参数列表。其中,param_name 为参数名,type 为参数的类型 (可以是任何有效的 MySQL 数据类型)。当有多个参数时,参数列表中彼此间用逗号分隔。存储过程可以没有参数( 此时存储过程的名称后仍需加上一对括号),也可以有一个或多个参数。 MySQL 存储过程支持三种类型的参数。即输入参数、输出参数和输入/输出参数,分别用 IN、OUT 和 INOUT 三个关键字标识。其中,输入参数是使数据可以传递给一个存储过程;输出参数用于存储过程需更返回一个操作结果的情形;而输入/输出参数既可以充当输入参数也可以充当输出参数。需要注意的是,参数的取名不要与数据表的列名相同,否则尽管不会返回出错消息,但是存储过程中的 SQL 语句会将参数名看作是列名,从而引发不可预知的结果。
- characteristic:存储过程的某些特征设定,下面分别介绍。
①COMMENT 'string':用于对存储过程的描述,其中 string 为描述内容,COMMENT 为关键字。这个描述信息可以用 SHOW CREATE PROCEDURE 语句来显示。
②LANGUAGE SQL:指明编写这个存储过程的语言为 SQL 语言。 目前而言,MySQL存储过程还不能用外部编程语言来编写,也就是说,这个选项可以不指定。今后 MySQL 将会对其扩展,最有可能第一个被支持的语言是 PHP。
③DETERMINISTIC:如若设置为 DETERMINISTIC,表示存储过程对同样的输入参数产生相同的结果;若设置为 NOT DETERMINISTIC,则表示会产生不确定的结果。 默认为 NOT DETERMINISTIC。
④CONTAINS SQL I NO SQL I READS SQL DATA I MODIFIES SQL DATA : CONTAINS SQL 表示存储过程包含读或写数据的语句;NO SQL 表示存储过程不包含 SQL 语句;READS SQL DATA表示存储过程包含读数据的语句,但不包含写数据的语句;MODIFIES SQL DATA 表示存储过程包含写数据的语句。若没有明确给定,则默认为 CONTAINS SQL。
⑤SQL SECURITY:这个特征用来指定存储过程使用创建该存储过程的用户( DEFINER)的许可来执行,还是使用调用者(INVOKER)的许可来执行。没有明确指定时,默认为 DEFINER。 - routine_body:存储过程的主体部分。 也称为存储过程体,其包含了在过程调用的时候必须执行的 SQL 语句。这个部分是以关键字 BEGIN 开始,以关键字 END 结束。如若存储过程体中只有一条 SQL 语句时,可以省略 BEGIN-END 标志。另外,在存储过程体中,BEGIN-END 复合语句还可以嵌套使用。
在存储过程的创建中,经常会用到一个十分重要的 MySQL 命令,即 DELIMITER 命令。
在 MySQL 中,服务器处理 SQL语句默认是以分号作为语句结束标志。然而,在创建存储过程时。在储过程体中可能包含有多条 SQL语句,这些 SQL 语句如果仍以分号作为语句结束符,那么 MySQL 服务器在处理时会以遇到的第一条 SQL 语句结尾处的分号作为整个程序的结束符,而不再去处理存储过程体中后面的 SQL 语句,这样显然不行。为解决这个问题,通常可使用 DELIMITER 命令,将 MySQL 语句的结束标志临时修改为其他符号,从而使得 MySQL 服务器可以完整地处理存储过程体中所有的 SQL 语句。
DELIMITER 命令的语法格式是:DELIMITER $$
语法说明如下:
- $$是用户定义的结束符。通常这个符号可以是一些特殊的符号,如两个"#"或两个"¥"等。
- 当使用 DELIMITER 命令时,应该避免使用反斜杠"\"字符,因为它是 MySQL的转义字符。
存储过程体
在存储过程体中可以使用各种 SQL 语句与过程式语句的组合,来封装数据库应用中复杂的业务逻辑和处理规则,以实现数据库应用的灵活编程。这里,主要介绍几个用于构造存储过程体的常用语法元素。
局部变量
在存储过程体中可以声明局部变量,用来存储存储过程体中的临时结果。在 MySQL 5.5 中,可以使用 DECLARE 语句来声明局部变量,并且同时还可以对该局部变量赋予一个初始值,其语法格式为:
DECLARE var_name[,...]type[DEFAULT value]
语法说明如下:
- var_name:用于指定局部变量的名称。
- type:用于声明局部变量的数据类型。
- DEFAULT 子句:用于为局部变量指定一个默认值。若没有指定,则默认为 NULL。
使用说明:
- 局部变量只能在存储过程体的 BEGIN...END 语句块中声明。 局部变量必须在存储过程体的开头处声明。
- 局部变量的作用范围仅限于声明它的 BEGIN...END 语句块,其他语句块中的语句不可以使用它。
- 局部变量不同于用户变量,两者的区别是:局部变量声明时,在其前面没有使用"@"符号,并且它只能被声明它的 BEGIN...END 语句块中的语句所使用;而用户变量在声明时,会在其名称前面使用"@"符号,同时已声明的用户变量存在于整个会话之中。
SET 语句
在 MySQL 5.5 中,可以使用 SET 语句为局部变量赋值,其语法格式是:SET var_name = expr[, var_name= expr]..
SELECT... INTO 语句
MySQL 5.5 中,可以使用 SELECT... INTO 语句把选定列的值直接存储到局部变量中,其语法格式是:SELECT col_name[,...]INTO var_name[,... ] table_expr
语法说明如下:
- col_name:用于指定列名。
- var_name:用于指定要赋值的变量名。
- table_expr:表示SELECT...INTO 语句返回的结果集只能有一行数据。
游标
在 MySQL中,一条 SELECT...INTO 语句成功执行后,会返回带有值的一行数据,这行数据可以被读取到存储过程中进行处理。然而,在使用 SELECT 语句进行数据检索时,若该语句被成功执行,则会返回一组称为结果集的数据行,该结果集中可能拥有多行数据,这些数据无法直接被一行一行地进行处理,此时就需要使用游标。游标是一个被 SELECT 请句检索出来的结果集。 在存储了游标后,应用程序或用户就可以根据需要滚动或浏览其中的数据。
在目前版本的 MySQL 中,若要使用游标,首先需要注意以下几点:
- MySQL对游标的支持是从 MySQL 5.0 开始的,之前的 MySQL 版本无法使用游标。
- 游标只能用于存储过程或存储函数中,不能单独在查询操作中使用。
- 在存储过程或存储函数中可以定义多个游标,但是在一个 BEGIN...END 语句块中每一个游标的名字必须是唯一的。
- 游标不是一条 SELECT 语句,是被 SELECT 语句检索出来的结果集。
在MySQL 5.5中,使用游标的具体步骤如下:
(1) 声明游标
在使用游标之前,必须先声明(定义)它。这个过程实际上没有检索数据,只是定义要使用 的 SELECT 语句。在 MySQL 5.5 中,可以使用 DECLARE CURSOR 语句创建游标,其语法格式为:DECLARE CURSOR FOR select_statement cursor_name
语法说明如下:
- cursor_name:指定要创建的游标的名称,其命名规则与表名相同。
- select_slalement:指定一条 SELECT 语句,其会返回一行或多行的数据。
注意:这里的 SELECT 语句不能有 INTO 子句。
(2) 打开游标
在定义游标之后,必须打开该游标,才能使用。这个过程实际上是将游标连接到由 SELECT 语句返回的结果集中。在 MySQL 5.5 中,可以使用 OPEN 语句打开游标,其语法格式是:OPEN cursor_name
其中,cursor_name 用于指定要打开的游标。
在实际应用中,一个游标可以被多次打开,由于其他用户或应用程序可能随时更新了数据表,因此每次打开游标的结果集可能会不同。
(3) 读取数据
对于填有数据的游标,可根据需要取出数据。 在 MySQL 5.5中,可以使用 FETCH...INTO 语句从中读取数据,其语法格式为:FETCH cursor_name INTO var_name[,var_name]...
语法说明如下:
- cursor_name:用于指定已打开的游标。
- var_name:用于指定存放数据的变量名。
FETCH...INTO 语句与 SELECT...INTO 语句具有相同的意义,FETCH 语句是将游标指向的一行数据赋给一些变量,这些变量的数目必须等于声明游标时 SELECT 子句中选择列的数目。 游标相当于一个指针,它指向当前的一行数据。
(4) 关闭游标
在结束游标使用时,必须关闭游标。在 MySQL 5.5 中,可以使用 CLOSE 语句关闭游标,其语法格式为:CLOSE cursor _name
其中,cursor_name用于要关闭的游标。
每个游标不再需要时都应该被关闭,使用 CLOSE 语句将会释放游标所使用的全部资源。在 一个游标被关闭后,如果没有重新被打开,则不能被使用。对于声明过的游标,则不需要再次声明。可直接使用 OPEN 语句打开。另外,如果没有明确关闭游标,MySQL 将会在到达 END 语句时自动关闭它。
例1:

sql
DELIMITER $$ //临时改变结束符(结束符设置为$$)
CREATE PROCEDURE sp_counter(OUT ROWS INT) //创建名为sp_counter的存储过程,设置为输出参数
BEGIN //触发器体开始
DECLARE cid INT; //声明局部变量
DECLARE FOUND BOOLEAN DEFAULT TRUE; //声明局部变量,默认值设置为TRUE
DECLARE cur_cid CURSOR FOR //声明游标
SELECT cno FROM tb_commodity;
DECLARE CONTINUE HANDLER FOR NOT FOUND //控制循环语句,以实现游标的下移
SET FOUND = FALSE;
SET ROWS = 0;
OPEN cur_cid; //打开游标
FETCH cur_cid INTO cid; //读取数据,其中cur_cid为游标的名称,cid为局部变量名
WHILE FOUND DO
SET ROWS = ROWS + 1;
FETCH cur_cid INTO cid;
END WHILE;
CLOSE cur_cid; //关闭游标
END $$ //触发器体结束,并用 $$ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第二行:OUT
②第十五行:FETCH
③第十七行:CLOSE
例2:

sql
DELIMITER $$ //临时改变结束符(结束符设置为$$)
CREATE PROCEDURE priceIncrementByCat(in p_catname CHAR(20), in p_increment decimal(10,2))
//创建名为priceIncrementByCat的存储过程,设置为输入参数
BEGIN //触发器体开始
UPDATE product p,category c SET p.price = p.price * (1 + p_increment)
WHERE p.cid = c.cid AND c.cname = p_catname;
IF(ROW_COUNT() = 0) THEN
SELECT '类别名称不存在、或者该类别中无商品!' AS Result;
ELSE
SELECT CONCAT('类别:"',p_catname,'"中,有', ROW_COUNT(),'件商品价格已被更新!') AS Result;
END IF;
END $$ //触发器体结束,并用 $$ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第二行:PROCEDURE
②第五行:p_catname
③第九行:ROW_COUNT()
DECIMAL 是 MySQL 中的一种高精度数值数据类型,语法:
DECIMAL(M, D)
- M (精度):表示数字的总位数(包括整数和小数部分)
- D (标度):表示小数点后的位数
例3:

sql
DELIMITER $$ //临时改变结束符(结束符设置为$$)
CREATE PROCEDURE sp_emp(OUT avgsalary FLOAT) //创建名为sp_emp的存储过程,设置为输出参数
BEGIN //触发器体开始
DECLARE ename VARCHAR(12); //声明局部变量-姓名
DECLARE edu VARCHAR(10); //声明局部变量-学历
DECLARE esalary FLOAT; //声明局部变量-工资
DECLARE totalsalary FLOAT; //声明局部变量-总工资
DECLARE count SMALLINT; //声明局部变量-市场部人数
DECLARE done INT DEFAULT -1;
DECLARE cur_emp CURSOR FOR
SELECT name, education, salary
FROM tb_emp INNER JOIN tb_dept
ON tb_emp.deptno = tb_dept.deptno AND deptname = '市场部';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
SET totalsalary = 0; //为局部变量赋值
SET count = 0; //为局部变量赋值
OPEN cur_emp; //打开游标
FETCH cur_emp INTO ename, edu, esalary; //读取数据,其中cur_emp为游标的名称,ename, edu, esalary为局部变量名
WHILE (done != 1) DO
SELECT ename, edu, esalary;
SET totalsalary = totalsalary + esalary; //工资累加
SET count = count + 1; //人数累加
FETCH cur_emp INTO ename, edu, esalary;
END WHILE;
IF (count > 0) THEN
SET avgsalary = totalsalary / count; //计算平均工资
ELSE
SET avgsalary = 0;
END IF;
CLOSE cur_emp; //关闭游标
END $$ //触发器体结束,并用 $$ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第二行:PROCEDURE
②第二十一行:p_catname
③第三十行:cur_emp
例4:

sql
DELIMITER $$ //临时改变结束符(结束符设置为$$)
CREATE PROCEDURE sp_list(IN s CHAR(20)) //创建名为sp_list的存储过程,设置为输入参数
BEGIN //触发器体开始
IF s != '' THEN
SELECT sname,smajor FROM tb_student s,tb_gs gs, tb_group g WHERE s.sno = gs.sno AND gs.gno = g.gno AND gname = s;
END IF;
END $$ //触发器体结束,并用 $$ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
CALL sp_list('话剧社');
空处:
①第二行:IN
②第四行:!=
③第五行:s(gname = s)
④第九行:CALL
例5:

sql
DELIMITER $$ //临时改变结束符(结束符设置为$$)
CREATE PROCEDURE sp_book(IN dept VARCHAR(20), OUT bookAvg FLOAT)
//创建名为sp_book的存储过程,dept设置为输入参数;bookAvg设置为输出参数
BEGIN //触发器体开始
DECLARE readerNum FLOAT; //声明局部变量
DECLARE borrowNum FLOAT; //声明局部变量
SELECT COUNT(*) INTO readerNum FROM tb_reader WHERE department = dept;
SELECT COUNT(*) INTO borrowNum FROM tb_borrow, tb_reader
WHERE tb_reader.readerNo = tb_borrow.readerNo AND department = dept GROUP BY department;
IF (readerNum > 0) THEN
SET bookAvg = borrowNum / readerNum; //求平均值
ELSE
SET bookAvg =0;
END IF;
END $$ //触发器体结束,并用 $$ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第二行:IN
②第二行:OUT
③第六行:dept
④第八行:group by后面的department
⑤第九行:0
例6:

sql
DELIMITER $ //临时改变结束符(结束符设置为$)
CREATE PROCEDURE sp_addorder(in goodsid int, in quantity int) //创建名为sp_addorder的存储过程,设置为输入参数
BEGIN //触发器体开始
declare pr double; //声明局部变量
select price into pr from goods where id = goodsid; //select 列名 into 变量名 from 表名
insert into orders(gid, quantity) values (goodsid, quantity);
update orders set total = pr * quantity where gid = goodsid;
END $ //触发器体结束,并用 $ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第五行:goodsid
②第六行:orders
③第七行:pr * quantity
例7:

sql
DELIMITER $ //临时改变结束符(结束符设置为$)
CREATE PROCEDURE sp_order(in gid int, in quantity int) //创建名为sp_order的存储过程,设置为输入参数
BEGIN //触发器体开始
declare remain int; //声明局部变量
insert into orders(gid, quantity) values (gid, quantity);
update goods set num = num - quantity where id = gid;
select num into remain from goods where id = gid; //select 列名 into 变量名 from 表名
select remain;
END $ //触发器体结束,并用 $ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第二行:in(in quantity int)
②第六行:goods
③第七行:gid
例8:

sql
USE XK; //指定为当前数据库
DELIMITERS $$ //临时改变结束符(结束符设置为$$)
CREATE PROCEDURE sp_update_room(IN cid INT, IN rno CHAR(20)) //创建名为sp_update_room的存储过程,设置为输入参数
BEGIN //触发器体开始
UPDATE course SET room = rno WHERE course_id = cid;
END $$ //触发器体结束,并用 $$ 表示整个定义结束
空处:
①第三行:PROCEDURE
②第五行:cid
③第六行:$$
例9:

sql
USE JY; //指定为当前数据库
DELIMITERS $$ //临时改变结束符(结束符设置为$$)
CREATE PROCEDURE sp_update_price //创建名为sp_update_price的存储过程
BEGIN //触发器体开始
UPDATE book SET price = price * 1.1 WHERE book_name LIKE "%计算机%";
END $$ //触发器体结束,并用 $$ 表示整个定义结束
空处:
①第三行:PROCEDURE
②第五行:book
③第五行:LIKE
例10:

sql
DELIMITER $$
CREATE PROCEDURE PR_学分(IN xh CHAR(10),OUT zxf INT)
//创建名为PR_学分的存储过程,,xh设置为输入参数;zxf设置为输出参数
BEGIN //触发器体开始
SELECT sum(课程学分) INTO zxf //select 列名 into 变量名 from 表名
FROM 选课, 课程
WHERE 选课.课程名称 = 课程.课程名称 AND 学号 = xh AND 成绩 >= 60;
END $$ //触发器体结束,并用 $$ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第二行:PROCEDURE
②第四行:zxf
③第六行:学号 = xh
存储函数
存储函数与存储过程之间存在几点区别:
- 存储函数不能拥有输出参数。这是因为存储函数自身就是输出参数;而存储过程可以拥有输出参数。 .
- 可以直接对存储函数进行调用,不需要使用 CALL语句;而对存储过程的调用,需要使用 CALL 语句。
- 存储函数中必须包含一条 RETURN 语句,而这条特殊的 SQL 语句不允许包含于存储过程中。
创建存储函数
在 MySQL 5.5 中,可以使用 CREATE FUNCTION 语句创建存储函数,其语法格式为:
sql
CREATE
FUNCTION sp_name([func_parameter[,...]])
RETURNS type
routine_body
其中 func_parameter 的格式为:param_name type
type 的格式为: Any valid MySQL data type
routine_body 的格式为:Valid SOL routine statement
由于 CREATE FUNCTION 语句与前面 CREATE PROCEDURE 语句的语法大致相同,故这里仅对两者有所区别的语法说明如下:
- sp_name:用于指定存储函数的名称。注意,存储函数不能与存储过程具有相同的名称。
- func_parameter:用于指定存储函数的参数。这里的参数只有名称和类型,不能指定关键字IN、OUT 和 INOUT。
- RETURNS 子句:用于声明存储函数返回值的数据类型。其中,type 用于指定返回值的数 . 据类型。
- routine_body:存储函数的主体部分,也称存储函数体。所有在存储过程中使用的 SQL 语句在存储函数中同样也适用。
调用存储函数
成功创建存储函数后,就可以如同调用系统内置函数一样,使用关键字SELECT对其进行调用,其语法格式是:SELECT sp_name([ func_parameter[,....]])
删除存储函数
存储函数在被创建后,会被保存在服务器上以供使用,直至被删除。 删除存储函数的方法与删除存储过程的方法基本 一样。 在 MySQL 5.5 中,可以使用 DROP FUNCTION 语句来实现,其语法格式为:DROP FUNCTION [ IF EXISTS ]sp_name
语法说明如下:
- sp_name:指定要删除的存储函数的名称。注意,它后面没有参数列表,也没有括号。在删除之前,必须确认该存储函数没有任何依赖关系,否则会导致其他与之关联的存储函数无法运行。
例1:

sql
DELIMITER $$ //临时改变结束符(结束符设置为$$)
//CREATE FUNCTION sp_name([func_parameter[,...]]) RETURNS type routine_body
CREATE FUNCTION fn_emp(dept CHAR(20)) //创建名为fn_emp的存储函数,其参数名为dept,类型为char
RETURNS FLOAT //声明存储函数返回值的数据类型
DETERMINISTIC //表示存储过程对同样的输入参数产生相同的结果
BEGIN //触发器体开始
Declare sum_salary float; //声明局部变量
SELECT sum(salary) INTO sum_salary //select 列名 into 变量名 from 表名
FROM tb_employee INNER JOIN tb_dept
ON tb_employee.deptno = tb_dept.deptno
WHERE dname = dept //与存储函数参数相等的值
GROUP BY dname ;
return sum_salary ; //返回局部变量的值
END $$ //触发器体结束,并用 $$ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第七行:INTO
②第九行:ON
③第十行:dname = dept
例2:

sql
DELIMITER $$ //临时改变结束符(结束符设置为$$)
CREATE FUNCTION fn_cmax(cn CHAR(20)) //创建名为fn_cmax的存储函数,其参数名为cn,类型为char
RETURNS int //声明存储函数返回值的数据类型
DETERMINISTIC //表示存储过程对同样的输入参数产生相同的结果
BEGIN //触发器体开始
DECLARE tmp INT; //声明局部变量
SELECT max(grade) INTO tmp //select 列名 into 变量名 from 表名
FROM tb_score
WHERE cname = cn; //与存储函数参数相等的值
RETURN tmp; //返回局部变量的值
END $$ //触发器体结束,并用 $$ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第二行:FUNCTION
②第七行:max(grade)
③第十行:tmp
例3:

sql
DELIMITER // //临时改变结束符(结束符设置为//)
CREATE FUNCTION fn_yggl(eid CHAR(4)) //创建名为fn_yggl的存储函数,其参数名为eid,类型为char
RETURNS CHAR(20) //声明存储函数返回值的数据类型
DETERMINISTIC //表示存储过程对同样的输入参数产生相同的结果
BEGIN //触发器体开始
DECLARE workage INT; //声明局部变量
DECLARE newsalary FLOAT; //声明局部变量
SELECT YEAR(CURDATE())-SUBSTRING(worktime,1,4) INTO workage FROM tb_emp WHERE eno = eid;
//select 列名 into 变量名 from 表名
IF workage >= 30 THEN
UPDATE tb_emp SET salary = salary * 1.05 WHERE eno = eid;
RETURN('工资已经更新');
ELSE
RETURN('工作年限不够,工资不能更新');
END IF;
END // //触发器体结束,并用 // 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
SELECT fn_yggl('1118'); //调用存储函数
空处:
①第三行:RETURNS
②第九行:workage
③第十七行:fn_yggl
例4:

sql
DELIMITER $ //临时改变结束符(结束符设置为$)
CREATE FUNCTION fn_orderdetail(name VARCHAR(20), oid INT) //创建名为fn_orderdetail的存储函数,其参数名为name,类型为char;oid,类型为int
RETURNS INT //声明存储函数返回值的数据类型
DETERMINISTIC //表示存储过程对同样的输入参数产生相同的结果
BEGIN //触发器体开始
declare tmp INT; //声明局部变量
SELECT quantity INTO tmp FROM goods, orders //select 列名 into 变量名 from 表名
WHERE goods.id = orders.gid AND goods.name = name AND orders.oid = oid;
RETURN tmp;
END$ //触发器体结束,并用 $ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第二行:FUNCTION
②第三行:RETURNS
③第八行:gid
例5:

sql
DELIMITER $$ //临时改变结束符(结束符设置为$$)
CREATE FUNCTION fn_学分(kcm char(20)) //创建名为fn_学分的存储函数,其参数名为kcm,类型为char
RETURNS INT //声明存储函数返回值的数据类型
DETERMINISTIC //表示存储过程对同样的输入参数产生相同的结果
BEGIN //触发器体开始
DECLARE xf int; //声明局部变量
SELECT 课程学分 INTO xf from 课程 //select 列名 into 变量名 from 表名
WHERE 课程名称 = kcm;
RETURN xf;
end $$ //触发器体结束,并用 $$ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第五行:BEGIN
②第八行:课程名称
③第九行:xf
例6:

sql
DELIMITER $$ //临时改变结束符(结束符设置为$$)
CREATE FUNCTION FN_平均成绩(XM VARCHAR(10)) //创建名为FN_平均成绩的存储函数,其参数名为XM,类型为varchar
RETURNS float //声明存储函数返回值的数据类型
DETERMINISTIC //表示存储过程对同样的输入参数产生相同的结果
BEGIN //触发器体开始
DECLARE Grade float; //声明局部变量
SELECT AVG(成绩) INTO Grade FROM 选课, 学生
WHERE 选课.学号 = 学生.学号 AND 姓名 = XM;
RETURN Grade ;
END $$ //触发器体结束,并用 $$ 表示整个定义结束
DELIMITER ; //恢复结束符为 ;
空处:
①第三行:RETURNS
②第六行:DECLARE
③第七行:Grade
| 存储过程(Procedure) | 存储函数(Function) | |
|---|---|---|
| 返回值 | 通过 OUT/INOUT 参数返回,可返回多个值 | 通过 RETURNS 语句返回单个值 |
| 调用方式 | 使用 CALL 过程名() | 使用SELECT 函数名() |
| 参数类型 | IN、OUT、INOUT | 只有 IN(默认),不能有 OUT/INOUT |
| RETURN 语句 | 没有 | 必须有,且返回一个值 |