MySQL中存储过程和存储函数以及触发器的基础知识

存储过程与存储函数

定义:

MySQL中提供存储过程与存储函数机制,我们姑且将存储过程和存储函数合称为存储程序。与一般的SQL语句需要先编译然后立即执行不同,存储程序是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,当用户通过指定存储程序的名字并给定参数(如果该存储程序带有参数)来调用才会执行。

存储程序就是一条或者多条SQL语句和控制语句的集合,我们可以将其看作MySQL的批处理文件,当然,其作用不仅限于批处理。当想要在不同的应用程序或平台上执行相同的功能一段程序或者封装特定功能时,存储程序是非常有用的。数据库中的存储程序可以看做是面向对编程中面向对象方法,它允许控制数据的访问方式。

存储函数与存储过程有如下区别:

(1)存储函数的限制比较多,例如不能用临时表,只能用表变量,而存储过程的限制较少,存储过程的实现功能要复杂些,而函数的实现功能针对性比较强。

(2)返回值不同。存储函数必须有返回值,且仅返回一个结果值;存储过程可以没有返回值,但是能返回结果集(out,inout)。

(3)调用时的不同。存储函数嵌入在SQL中使用,可以在select 存储函数名(变量值);存储过程通过call语句调用 call 存储过程名。

(4)参数的不同。存储函数的参数类型类似于IN参数,没有类似于OUT和INOUT的参数。存储过程的参数类型有三种,IN、out和INOUT:

a. in:数据只是从外部传入内部使用(值传递),可以是数值也可以是变量

b. out:只允许过程内部使用(不用外部数据),给外部使用的(引用传递:外部的数据会被先清空才会进入到内部),只能是变量

c. inout:外部可以在内部使用,内部修改的也可以给外部使用,典型的引用 传递,只能传递变量。

1.存储过程

创建存储过程语法结构如下:

CREATE PROCEDURE  过程名([[IN|OUT|INOUT] 参数名 数据类型[,[IN|OUT|INOUT] 参数名 数据类型…]]) [特性 ...]

BEGIN

    过程体

END

MySQL中存储过程和存储函数以及触发器的基础知识_第1张图片

建好表后,我们来创建一个存储过程。

示例1:通过存储过程完成查询每个员工编号(empno)、姓名(ename)、职位(job)、领导编号(mgr)、领导姓名(empno)、部门名称(dname)、部门位置(loc)。

delimiter //

create procedure select_pro()

         begin

                   select e1.empno bianhao, e1.ename xingming, e1.job zhiwei, e1.mgr lindaobianhao, e2.ename lindaoxingming, d.dname bumenmingchen, 
                d.loc bumenweizhi

                   from emp e1 , emp e2 , dept d

                   where e1.mgr=e2.empno and e1.deptno=d.deptno ;

         end //

delimiter ;

注:“delimiter //”语句的作用是将MySQL的结束符设置为//,因为MySQL默认的语句结束符是分号“;”,为了避免与存储过程中的SQL语句结束符相冲突,需要使用delimiter改变存储过程的结束符,设置为以“end //”结束存储过程。存储过程定义完毕之后,再使用“delimiter;”回复默认结束符。delimiter也可以指定其他符号作为结束符(“\”除外,这是转义字符)。当然,如果你在Navicat等图形界面下进行,可以不用设置delimiter。

示例1中SQL语句创建了一个名为select_pro的存储过程,通过“call select_pro()”,即可完成查询功能,不在需要每次查询都重写查询语句。

示例2:创建一个带参数的存储过程,删除emp表中empno为指定值得记录,并返回最高最高月薪,也返回大于指定月薪的人数。

复制代码
delimiter //

create procedure param_pro(in id int , out num int, inout p_sal int)

         begin

                   delete from emp where empno = id ;

                   select max(sal) from emp into num;

                   select count(*)  into p_sal from emp where sal >P_sal ;

         end //

delimiter ;

调用上面创建好的存储过程param_pro:

set @p_sal = 1250 ;

call param_pro(7369 , @num , @p_sal);

select @num , @p_sal ;

MySQL中存储过程和存储函数以及触发器的基础知识_第2张图片

2.存储函数

创建存储函数:

CREATE FUNCTION  函数名([ 参数名 数据类型 [,]]) RETURNS返回类型

BEGIN

  过程体

END

存储过程与存储函数一个很大的不同就是制定参数IN、OUT、INOUT只对存储过程有用,存储函数默认IN类型参数,不能设置其他两种类型。RETURNS子句声明返回值类型也只能在存储函数中使用,且一个存储函数必须包含一个RETURNS 语句。

示例3:用存储函数查询指定empno的员工的月薪sal

复制代码
delimiter //

create function fun1(id int) returns int

         begin

                   return (select sal from emp where empno=id);

         end //

delimiter ;

调用存储函数fun1:

select fun1(7698)

在这里插入图片描述

3.修改存储过程和函数

使用ALTER语句可以修改存储过程和函数的特性。语法结构如下:

ALTER {PROCEDURE | FUNCTION} sp_name [characteristic …]

其中,sp_name表示存储过程或函数的名称,characteristic参数指定存储过程或函数的特性,可能取值有:

CONTAINS SQL:子程序包含SQL语句,但不包含读或写数据的语句。

NO SQL:子程序不包含SQL语句。

READS SQL DATA:子程序包含读数据的语句。

MODIFIES SQL DATA:子程序包含写数据的语句。

SQL SECURITY { DEFINER | INVOKER}:指明谁有权限执行。

DEFINER:只有定义者自己才能执行。

INVOKER:调用者可以执行。

COMMENT ‘string’ :注释。

示例4:示例1中创建的存储过程param_pro,将其读写权限该为MODIFIES SQL DATA,并指明调用者可以执行。

ALTER PROCEDURE param_pro

MODIFIES SQL DATA

SQL SECURITY INVOKER ;

课后练习:

#第十五章_存储过程与存储函数_课后练习
#0.准备工作
CREATE DATABASE dbtest15_pro_func;
USE dbtest15_pro_func;
#1. 创建存储过程insert_user(),实现传入用户名和密码,插入到admin表中
CREATE TABLE admin(
id INT PRIMARY KEY AUTO_INCREMENT,
user_name VARCHAR(15) NOT NULL,
pwd VARCHAR(25) NOT NULL
);

DELIMITER //
CREATE PROCEDURE  insert_user (IN r VARCHAR(20),IN ps VARCHAR(20))
BEGIN
     INSERT INTO admin(user_name,pwd)
		 VALUES (r,ps);
END //
DELIMITER ;

CALL insert_user('denghao','1258252414');

SELECT * FROM admin;

#2. 创建存储过程get_phone(),实现传入女神编号,返回女神姓名和女神电话
CREATE TABLE beauty(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(15) NOT NULL,
phone VARCHAR(15) UNIQUE,
birth DATE
);
DESC beauty;
INSERT INTO beauty(NAME,phone,birth)
VALUES
('朱茵','13201233453','1982-02-12'),
('孙燕姿','13501233653','1980-12-09'),
('田馥甄','13651238755','1983-08-21'),
('邓紫棋','17843283452','1991-11-12'),
('刘若英','18635575464','1989-05-18'),
('杨超越','13761238755','1994-05-11');
SELECT * FROM beauty;
DELIMITER //
CREATE PROCEDURE get_phone(IN id INT,OUT NAME VARCHAR(20),OUT phone VARCHAR(20))
BEGIN
SELECT b.name ,b.phone INTO NAME,phone
FROM beauty b
WHERE b.id = id;
END //
DELIMITER ;

SET @id = 3;

CALL get_phone(@id,@name,@phone);

SELECT @name,@phone;

DELIMITER //
CREATE PROCEDURE data_diff(IN date1 DATE, IN date2 DATE,OUT result INT)
BEGIN
SELECT DATEDIFF(date1,date2) INTO result;
END //
DELIMITER ;

触发器

定义:

MySQL从 5.0.2 版本开始支持触发器。MySQL的触发器和存储过程一样,都是嵌入到MySQL服务器的一
段程序。
触发器是由 事件来触发 某个操作,这些事件包括 INSERT 、 UPDATE 、 DELETE 事件。所谓事件就是指
用户的动作或者触发某项行为。如果定义了触发程序,当数据库执行这些语句时候,就相当于事件发生
了,就会 自动 激发触发器执行相应的操作。
当对数据表中的数据执行插入、更新和删除操作,需要自动执行一些数据库逻辑时,可以使用触发器来
实现。

1.触发器的创建

CREATE TRIGGER 触发器名称
{BEFORE|AFTER} {INSERT|UPDATE|DELETE} ON 表名
FOR EACH ROW
触发器执行的语句块;

表名 :表示触发器监控的对象。
BEFORE|AFTER :表示触发的时间。BEFORE 表示在事件之前触发;AFTER 表示在事件之后触发。
INSERT|UPDATE|DELETE :表示触发的事件。
INSERT 表示插入记录时触发;
UPDATE 表示更新记录时触发;
DELETE 表示删除记录时触发。

2.代码举例:

1、创建数据表:
2、创建触发器:创建名称为before_insert的触发器,向test_trigger数据表插入数据之前,向
test_trigger_log数据表中插入before_insert的日志信息。
3、向test_trigger数据表中插入数据
4、查看test_trigger_log数据表中的数据
1.
CREATE TABLE test_trigger (
id INT PRIMARY KEY AUTO_INCREMENT,
t_note VARCHAR(30)
);
CREATE TABLE test_trigger_log (
id INT PRIMARY KEY AUTO_INCREMENT,
t_log VARCHAR(30)
);
2.
DELIMITER //
CREATE TRIGGER before_insert
BEFORE INSERT ON test_trigger
FOR EACH ROW
BEGIN
INSERT INTO test_trigger_log (t_log)
VALUES('before_insert');
END //
DELIMITER ;
3.
INSERT INTO test_trigger (t_note) VALUES ('测试 BEFORE INSERT 触发器');
4.
mysql> SELECT * FROM test_trigger_log;
+----+---------------+
| id | t_log |
+----+---------------+
| 1 | before_insert |
+----+---------------+
1 row in set (0.00 sec)
举例21、创建名称为after_insert的触发器,向test_trigger数据表插入数据之后,向test_trigger_log数据表中插
入after_insert的日志信息。
DELIMITER //
CREATE TRIGGER after_insert
AFTER INSERT ON test_trigger
FOR EACH ROW
BEGIN
	INSERT INTO test_trigger_log (t_log)
	VALUES('after_insert');
END //
DELIMITER ;
2、向test_trigger数据表中插入数据。
INSERT INTO test_trigger (t_note) VALUES ('测试 AFTER INSERT 触发器');
3、查看test_trigger_log数据表中的数据
mysql> SELECT * FROM test_trigger_log;
+----+---------------+
| id | t_log |
+----+---------------+
| 1 | before_insert |
| 2 | before_insert |
| 3 | after_insert |
+----+---------------+
3 rows in set (0.00 sec)
举例3:定义触发器“salary_check_trigger”,基于员工表“employees”的INSERT事件,在INSERT之前检查
将要添加的新员工薪资是否大于他领导的薪资,如果大于领导薪资,则报sqlstate_value为'HY000'的错
误,从而使得添加失败。
DELIMITER //
CREATE TRIGGER salary_check_trigger
BEFORE INSERT ON employees FOR EACH ROW
BEGIN
	DECLARE mgrsalary DOUBLE;
	SELECT salary INTO mgrsalary FROM employees WHERE employee_id = NEW.manager_id;
	
	IF NEW.salary > mgrsalary THEN
		SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = '薪资高于领导薪资错误';
	END IF;
END //
DELIMITER ;

3.查看、删除触发器

查看

方式1:查看当前数据库的所有触发器的定义

SHOW TRIGGERS\G

方式2:查看当前数据库中某个触发器的定义

SHOW CREATE TRIGGER 触发器名

方式3:从系统库information_schema的TRIGGERS表中查询“salary_check_trigger”触发器的信息。

SELECT * FROM information_schema.TRIGGERS;
删除

触发器也是数据库对象,删除触发器也用DROP语句,语法格式如下:

DROP TRIGGER IF EXISTS 触发器名称;

你可能感兴趣的:(MySQL,mysql,数据库,sql)