mysql数据库应用fileapi.it.hactcm.edu.cn › mysql › file › 2020 › 5 › 22 ›...
TRANSCRIPT
MySQL数据库应用
河南中医药大学信息技术学院 王昂
2019.02
第 2 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
第六章 MySQL过程式数据库对象
主讲内容:存储过程、存储函数、触发器、事件
第 3 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
教学内容
1. 存储过程
2. 存储函数
3. 触发器
4. 事件
第 4 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.1.3游标及其应用
一条select……into语句返回的是带有值的一行,这样可以把数据读
取到存储过程中,但是常规的select查询语句可以返回多行记录,如果
数据量非常大,这就需要在存储过程中使用游标来逐条读取查询结果集
中的数据。
使用游标需要用到4条特殊语句,分别是:
− DECLARE CURSOR(声明游标)
− OPEN CURSOR(打开游标)
− FETCH CURSOR(读取游标)
− CLOSE CURSOR(关闭游标)
第 5 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.1.3游标及其应用
(1)声明游标 语法格式:
DECLARE 游标名 CURSOR FOR select语句
说明:
- 游标只能在存储过程或存储函数中使用。
- 一个块中的每一个游标必须有唯一的名字。
- 上述SELECT语句不能有INTO子句。
第 6 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.1.3游标及其应用
下面的定义符合一个游标声明:
declare xs_cur1 cursor for select 学号,姓名,性别,出生日期,总学分 from xs where 专业名 = '计算机';
第 7 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.1.3游标及其应用
(2)打开游标
声明游标后,要使用游标从中提取数据,就必须先打开游标。
使用OPEN语句打开游标,其格式为:
OPEN 游标名
例如:打开游标xs_cur1。
open xs_cur1
第 8 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.1.3游标及其应用
(3)读取数据
游标打开后,就可以使用FETCH…INTO语句从中读取数据。
语法格式:
FETCH 游标名 INTO 变量名 ...
说明:
- FETCH ...INTO语句与SELECT...INTO语句具有相同的意义;
- FETCH语句是将游标指向的一行数据赋给一些变量, FETCH子句中变量
的数目必须等于声明游标时SELECT子句中列的数目。
将查询到的数据存储在变量中,因此需要读取刚才打开过的游标:
fetch xs_cur1 into xh,xm,xb,csrq,zxf;
第 9 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.1.3游标及其应用
(4)关闭游标
游标使用完以后,要及时关闭。关闭游标使用CLOSE语句。
语法格式为:
CLOSE 游标名
例如:关闭游标xs_cur1。
CLOSE xs_cur1
第 10 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.1.3游标及其应用
【例6.9】创建一个存储过程,计算xs表中行的数目。 delimiter $$ create procedure compute(out number integer) begin declare xh char(6); declare found boolean default true; declare number_xs cursor for select 学号 from xs; declare continue handler for not found set found=false; set number=0; open number_xs; fetch number_xs into xh; while found do set number=number+1; fetch number_xs into xh; end while; close number_xs; end$$ delimiter ; call compute(@num); select @num;
number_xs :游标名
第 11 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2 存储函数
存储函数也是过程式对象乊一,创建存储函数与存储过程大致相同。 1.创建存储函数CREATE FUNCTION 语法格式: CREATE FUNCTION 存储过程名 ([参数 ... ]) RETURNS type [特征 ...] 存储函数体 说明:
- 存储函数不能拥有与存储过程相同的名字。
- 存储函数的参数只有名称和类型,不能指定IN、OUT和INOUT。
- RETURNS type子句声明函数返回值的数据类型。
- 存储函数体:存储函数体中必须包含一个RETURN value语句。
第 12 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2.1 创建存储函数
【例6.15】创建一个存储函数,它返回xs表中学生的数目作为结果。 delimiter $$ create function num_of_xs( ) returns integer begin return (select count(*) from xs); end$$ delimiter ; 说明:RETURN子句中包含SELECT语句时,SELECT语句的返回结果只能
是一行且只能有一列值。
第 13 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2.1 创建存储函数
【例6.16】创建一个存储函数,返回某个学生的姓名。 delimiter $$ create function name_of_stu(xh char(6)) returns char(8) begin return (select 姓名 from xs where 学号=xh); end$$ delimiter ;
第 14 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2.1 创建存储函数
【例6.17】创建一个存储函数来删除xs_kc表中有,但xs表中丌存在的学号。如果调用存储函数时,参数中的学号在xs表中丌存在,那么将删除xs_kc表中所有不该学号相关的行,之后返回1。如果学号在xs中存在则直接返回零。
delimiter $$ create function delete_stu(xh char(6)) returns boolean begin declare stu char(6); select 姓名 into stu from xs where 学号=xh; if stu is null then delete from xs_kc where 学号=xh; return true; else return false; end if; end$$ delimiter ;
第 15 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2.2 存储函数的调用、删除和修改
1. 存储函数的调用 存储函数创建完后,就如同系统提供的内置函数(如VERSION()),
所以调用存储函数的方法也差不多,都是使用SELECT关键字。 语法格式:
SELECT 存储函数名 ([参数[,...]]) 例如,无参数调用存储函数。命令如下: select num_of_xs(); 执行结果如图所示。
例如,有参数调用存储函数。命令如下: select name_of_stu('081106'); 执行结果如图所示。
第 16 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2.2 存储函数的调用、删除和修改
【例6.18】创建一个存储函数,通过调用存储函数NAME_OF_STU获得学号的姓名,判断姓名是否是“王林”,是则返回王林的出生日期,丌是则返回“FALSE”。
delimiter $$ create function is_stu(xh char(6)) returns char(10) begin declare name char(8); select name_of_stu(xh) into name; if name= '王林' then return(select 出生日期 from xs where 学号=xh); else return 'false'; end if; end$$ delimiter ;
第 17 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2.2 存储函数的调用、删除和修改
接着调用存储函数is_stu查看结果:
select is_stu('081102');
执行结果如图所示。
select is_stu('081101');
执行结果如图所示。
第 18 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2.2 存储函数的调用、删除和修改
2. 删除存储函数
删除存储函数与删除存储过程的方法基本一样,都使用DROP
FUNCTION语句。
语法格式:
DROP FUNCTION [IF EXISTS] 存储过程名
例如,删除存储函数num_of_xs。 drop function if exists num_of_xs;
第 19 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2.2 存储函数的调用、删除和修改
3、使用ALTER FUNCTION语句可以修改存储函数的特征。
语法格式:
ALTER FUNCTION 存储过程名 [特征 ...] 注意:要修改存储函数的内容则要采用先删除后定义的方法。
第 20 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2.2 存储函数的调用、删除和修改
4、使用SHOW STATUS语句
Show status语句可以查看存储过程或存储函数所操作的数据库对
象,例如:存储过程或存储函数的名称、类型、定义、修改时间等信息
show [ procedure | function ] status [like‘pattern’]
说明:
like‘pattern’表示可以匹配存储过程或存储函数名称。
第 21 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.2.2 存储函数的调用、删除和修改
5、使用show create 语句
Show create语句可以查看存储过程或存储函数的详细定义状态,
例如:存储过程或存储函数的字符集等信息。
show create [ procedure | function ] sp_name
说明:
sp_name表示存储过程或存储函数的名称。
第 22 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
练习
1、创建一个存储函数count1_xs,用于统计xs表中男生的总人数;
2、创建一个存储函数stu_zhuanye,根据指定的学生学号,返回该学
生所在的专业名。
3、创建一个存储函数,通过调用存储函数stu_zhuanye获得学生的专
业名,然后返回该专业的总人数。
第 23 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
练习
1、创建一个存储函数count1_xs,用于统计xs表中男生的总人数;
delimiter $$ create function count1_xs() returns integer begin return (select count(*) from xs where 性别=1); end$$ delimiter ; select count1_xs(); select count(*) from xs where 性别=1;
第 24 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
练习
2、创建一个存储函数stu_zhuanye,根据指定的学生学号,返回该学生所在的专业名。
delimiter $$ create function stu_zhuanye( xh char(6)) returns char(10) begin return (select 专业名 from xs where 学号=xh); end$$ delimiter ; select stu_zhuanye(‘081101’); select 专业名 from xs where 学号=‘081101’;
第 25 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
练习
3、创建一个存储函数,通过调用存储函数stu_zhuanye获得学生的专业名,然后返回该专业的总人数。
delimiter $$ create function count_zhuanye( xh char(6)) returns integer begin declare zhuanye char(10); select stu_zhuanye(xh) into zhuanye; return (select count(*) from xs where 专业=zhuanye); end$$ delimiter ; select count_zhuanye(‘081101’);
第 26 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
1、存储函数不能拥有输出参数,由于存储函数本身就是输出参数;而存储过程可
以拥有输出参数;
2、存储函数只能返回单个值,而存储过程可以通过out参数返回多个值;
3、可以直接对存储函数进行调用,而不需要使用call语句;而对存储过程的调用
,需要使用call语句;
4、存储函数中必须包含一条return语句,而这条特殊的sql语句不允许包含在存储
过程中。
5、存储函数可以嵌套在sql语句中使用,比如可以在select语句中作为查询语句的
一个部分调用,但是存储过程一般是作为一个独立的部分来执行。
思考??
MySQL存储过程和存储函数有什么区别?
第 27 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.3 触发器 触发器是一种维护数据的完整性或者执行其它特殊任务的存储过程。
当有操作影响到触发器保护的数据时,触发器自动执行。 1. 创建触发器CREATE TRIGGER 语法格式:
CREATE TRIGGER 触发器名 触发时刻 触发事件 ON 表名 FOR EACH ROW 触发器动作
说明: - 触发时刻:有两个选项BEFORE和AFTER,以表示触发器是在激活它
的语句之前或之后触发。
- 触发事件:指明了激活触发程序的语句的类型,可以是insert、
delete或者update。
第 28 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.3 触发器
-表名:表示在该表上发生触发事件才会激活触发器。同一个表不能
拥有两个具有相同触发时刻和事件的触发器。
例如,对于某一表,不能有两个BEFORE UPDATE触发器,但可以有1个BEFORE
UPDATE触发器和1个BEFORE INSERT触发器,或1个BEFORE UPDATE触发器和1个AFTER
UPDATE触发器。
-FOR EACH ROW:对于受触发事件影响的每一行,都要激活触发
器的动作。
例如,使用一条语句向一个表中添加多个行,触发器会对每一行执行相应触发
器动作。
-触发器动作:包含触发器激活时将要执行的语句。如果要执行多个
语句,可使用BEGIN ... END复合语句结构。
第 29 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.3 触发器
【例6.19】创建一个表table1,其中只有一列a。在表上创建一个触发
器,每次插入操作时,将用户变量str的值设为“trigger is working”。
create table table1(a integer); create trigger table1_insert after insert on table1 for each row set @str= ' trigger is working ';
insert into table1 values(10);
select @str;
执行结果如图所示。
第 30 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.3 触发器
(1)触发器中关联表中的列
在MySQL触发器中的SQL语句可以关联表中的任意列。但不能直接使用
列的名称去标志,那会使系统混淆,因为激活触发器的语句可能已经修改、
删除或添加了新的列名,而列的旧名同时存在。
因此必须用‚NEW.列名‛引用新行的一列,用‚OLD.列名‛引用更新
或删除它之前的已有行的一列。
注意:
- 对于INSERT触发事件,只有NEW是合法的;
- 对于DELETE触发事件,只有OLD才合法;
- 而UPDATE触发事件可以与NEW或OLD同时使用。
第 31 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.3 触发器
【例6.20】创建一个触发器,当删除表xs中某个学生的信息时,同时将xs_kc表中不该学生有关的数据全部删除。
delimiter $$ create trigger xs_delete after delete on xs for each row begin delete from xs_kc where 学号=old.学号; end$$ delimiter ; delete from xs where 学号='081101'; select * from xs_kc;
第 32 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.3 触发器
【例6.21】创建一个触发器,当修改xs_kc表中数据时,如果修改后的成绩小于60分,则触发器将该成绩对应的课程学分修改为0,否则将学分改成对应课程的学分。
delimiter $$ create trigger xs_kc_update before update on xs_kc for each row begin declare xf int(1); select 学分 into xf from kc where 课程号=new.课程号; if new.成绩<60 then set new.学分=0; else set new.学分=xf; end if; end$$ delimiter ;
第 33 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.3 触发器
【例6.22】创建触发器,实现当向xs_kc表插入一行数据时,根据成绩对xs表的总学分进行修改。如果成绩>=60,总学分加上该课程的学分,否则总学分丌变。
delimiter $$ create trigger xs_kc_zxf after insert on xs_kc for each row begin declare xf int(1); select 学分 into xf from kc where 课程号=new.课程号; if new.成绩>=60 then update xs set 总学分=总学分+xf where 学号=new.学号; end if; end$$ delimiter;
第 34 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.3 触发器
(2)触发器中调用存储过程
在触发器中还可以调用存储过程。
【例6.23】假设xscj数据库中有一个不xs表结构完全一样的表
student,创建一个触发器,在xs表中添加数据的时候,调用存储过程,
将student表中的数据不xs表同步。
定义存储过程:
delimiter $$ create procedure changes() begin replace into student select * from xs; end$$ delimiter;
第 35 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.3 触发器
接着创建触发器: create trigger student_change after insert on xs for each row call changes(); 验证: insert into xs values('091102', '王大庆', '计算机', 1, '1994-08-14', 48, null,null); select * from student; 执行结果为:
第 36 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.3 触发器
2. 触发器删除
和其他数据库对象一样,使用DROP语句即可将触发器从数据库中删除。
语法格式:
DROP TRIGGER [schema_name.]trigger_name
说明:
- trigger_name指要删除的触发器名称。
- schema_name为所在数据库的名称,如果在当前数据库,可以省略。
例如,删除触发器xs_delete。 drop trigger xs_delete;
第 37 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.4 事件
触发器是在某些事情发生的时候启动,而事件是在满足相应时刻的时
候启动,都是数据库的过程式数据库对象。创建事件可以使用CREATE
EVENT语句。
语法格式:
CREATE EVENT 事件名
ON SCHEDULE schedule
[ON COMPLETION [NOT] PRESERVE]
[ENABLE | DISABLE | DISABLE ON SLAVE]
[COMMENT 'comment']
DO sql语句;
第 38 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.4.1 创建事件
(1)schedule格式:
AT 时间点 [+ INTERVAL 时间间隔]
| EVERY 时间间隔
[ STARTS 时间点[+ INTERVAL时间间隔]]
[ ENDS 时间点[+ INTERVAL时间间隔]]
说明:
- schedule:时间调度,表示事件何时发生或者每隔多久发生一次。 - AT子句:表示在某个时刻事件发生。在指定时间点,后面可以加上一个时间间
隔,由一个数值和单位构成,count是间隔时间的数值。 - EVERY子句:表示在指定时间区间内每隔多长时间事件发生一次。 - STARTS子句指定开始时间。 - ENDS子句指定结束时间。
第 39 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.4.1 创建事件
(2)interval 格式
count { YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND }
第 40 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.4.1 创建事件
(3)sql语句:
包含事件启动时执行的代码。如果包含多条语句,可以使用
BEGIN…END复合结构。
(4)事件的属性:
对于每一个事件都可以定义几个属性。
- ON COMPLETION [NOT] PRESERVE:NOT表示事件最后一次调用后将自动删除该事件
(默认),否则最后一次调用后将保留该事件。
- ENABLE | DISABLE | DISABLE ON SLAVE:
- ENABLE表示该事件是活动的,活动意味着调度器检查事件动作是否必须调用。
- DISABLE表示该事件是关闭的,关闭意味着事件的声明存储到目录中,但是调度
器不会检查它是否应该调用。
- DISABLE ON SLAVE表示事件在从机中是关闭的。如果不指定任何选项,在一个
事件创建之后,它立即变为活动的。
第 41 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.4.1 创建事件
一个打开的事件可以执行一次或多次,一个事件的执行称作调用事件。每次调用一个事件,MySQL都处理事件动作。
MySQL事件调度器负责调用事件。这个模块是MySQL数据库服务器的一部分。它不断地监视一个事件是否需要调用。
要创建事件,必须打开调度器。可以使用系统变量EVENT_SCHEDULER来打开事件调度器,TRUE为打开,FALSE为关闭:
SET GLOBAL EVENT_SCHEDULER = TRUE;
【例6.24】创建一个立即启动的事件。
create event direct on schedule at now() do insert into xs values('091103', '张建', '软件工程', 1,
'1994-06-05', 50,null,null);
第 42 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.4.1 创建事件
【例6.25】创建一个30秒后启动的事件。 create event thrityseconds on schedule at now()+interval 30 second do insert into xs values('091104', '陈建', '软件工程', 1,
'1994-08-16', 50,null,null);
第 43 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.4.1 创建事件
【例6.26】创建一个事件,它每个月启动一次,开始于下一个月并且在2014年的12月31日结束。
delimiter $$ create event startmonth on schedule every 1 month starts curdate()+interval 1 month ends '2014-12-31' do begin if year(curdate())<2014 then insert into xs values('091105', '王建', '软件工程', 1, '1994-03-
16',48,null,null); end if; end$$ delimiter ;
第 44 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.4.2 修改和删除事件
1. 修改事件 事件在创建后可以通过ALTER EVENT语句来修改其定义和相关属性。ALTER
EVENT语句与CREATE EVENT语句格式相仿,用户可以使用一条ALTER EVENT语句让
一个事件关闭或再次让它活动。当然,如果一个事件最后一次调用后已经不存在
了,就无法修改了。
语法格式: ALTER EVENT event_name [ON SCHEDULE schedule] [ON COMPLETION [NOT] PRESERVE] [RENAME TO new_event_name] [ENABLE | DISABLE | DISABLE ON SLAVE] [COMMENT 'comment'] [DO sql_statement] 说明:用户还可以使用一条RENAME TO子句修改事件的名称。
第 45 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.4.2 修改和删除事件
【例6.27】将事件startmonth的名字改成firstmonth。 alter event startmonth rename to firstmonth;
第 46 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
6.4.2 修改和删除事件
2. 删除事件
删除事件,语法格式:
DROP EVENT [IF EXISTS][database name.] event name
例如,删除名为direct的事件。
drop event direct;
第 47 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
案例 create table test1(a1 int); create table test2(a2 int); create table test3(a3 int not null auto_increment primary key); create table test4 (a4 int not null auto_increment primary key,b4 int default 0); delimiter $$ create trigger testref before insert on test1 for each row begin insert into test2 set a2=new.a1; Delete from test3 where a3=new.a1; Update test4 set b4=b4+1 where a4=new.a1; end$$ delimiter ; Insert into test3(a3) values (null), (null), (null), (null), (null),(null),
(null), (null), (null), (null); Insert into test4(a4) values (0), (0), (0), (0), (0), (0), (0), (0), (0), (0); Insert into test1 values (1),(3),(1),(7),(1),(8),(4),(4);
第 48 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
案例
执行下列查询语句后,每个表的结果?
Select * from test1;
Select * from test2;
Select * from test3;
Select * from test4;
第 49 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
案例 create table test1(a1 int); create table test2(a2 int); create table test3(a3 int not null auto_increment primary key); create table test4 (a4 int not null auto_increment primary key,b4 int default 0); delimiter $$ create trigger testref before insert on test1 for each row begin insert into test2 set a2=new.a1; Delete from test3 where a3=new.a1; Update test4 set b4=b4+1 where a4=new.a1; end$$ delimiter ; Insert into test3(a3) values (null), (null), (null), (null), (null),(null),
(null), (null), (null), (null); Insert into test4(a4) values (0), (0), (0), (0), (0), (0), (0), (0), (0), (0); Insert into test1 values (1),(3),(1),(7),(1),(8),(4),(4);
第 50 页 《MySQL数据库应用》 http://mysql.xg.hactcm.edu.cn/
案例
Select * from test1;
Select * from test2;
Select * from test3;
Select * from test4;