第五章:存储过程和触发器

🌈个人主页:小新_-

🎈个人座右铭:"成功者不是从不失败的人,而是从不放弃的人!"🎈

🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝

🏆所属专栏**:Oracle网络数据库** 欢迎订阅,持续更新中~~~

✨让小新带着你快乐的学习吧~✨

目录

一、存储过程

(一)存储过程的创建

1.以命令方式创建存储过程

2.以界面方式创建存储过程

(二)存储过程的调用

(三)存储过程的修改

[二、触 发 器](#二、触 发 器)

(一)以命令方式创建触发器

1.创建DML触发器

​编辑

2.创建替代触发器

3.创建系统触发器

(二)触发器的删除

1.以命令方式删除触发器

2.以界面方式删除触发器


存储过程是数据库对象之一,存储过程可以理解成数据库的子程序,在客户端和服务器端可以直接调用它。触发器是与表直接关联的特殊存储过程,是在对表记录进行操作时出发点的。

一、存储过程

在Oracle 11g中,可以在数据库中定义子程序,这种程序块称为存储过程(procedure)。它存放在数据字典中,可以在不同用户和应用程序之间共享,并可实现程序的优化和重用。存储过程的优点如下。

(一)存储过程的创建

1.以命令方式创建存储过程

创建存储过程使用CREATE PROCEDURE语句,语法格式为:

sql 复制代码
CREATE [OR REPLACE] PROCEDURE <过程名>  			/*定义过程名*/
	[ (<参数名> <参数类型> <数据类型> [ DEFAULT <默认值>] [, ...n])]
								/*定义参数类型及属性*/
{ IS | AS }
	[<变量声明>]						/*变量声明部分*/
	BEGIN
		<过程体>					/*PL/SQL过程体*/
	END [<过程名>][;]

相关参数说明如下:

(1)过程名:存储过程名称要符合标识符规则,并且在所属方案中必须是唯一的 。关键字OR REPLACE表示在创建存储过程时,如果已存在同名的过程,则重新创建。

(2)参数名:存储过程的参数名也要符合标识符规则,创建过程时,可以声明一个或多个参数,执行过程时应提供相对应的参数。存储过程的参数模式和函数参数一样,也有三种模式,分别为IN、OUT和IN OUT。

(3)DEFAULT:指定过程中IN参数的默认值,默认值必须是常量

(4)过程体:其中包含PL/SQL语句块。

在存储过程的定义体中,不能使用下列对象创建语句:

sql 复制代码
CREATE VIEW
CREATE DEFAULT
CREATE RULE 
CREATE PROCEDURE
CREATE TRIGGER

【例1】 创建一个简单的存储过程,输出hello world。

sql 复制代码
CREATE PROCEDURE proc
AS
BEGIN
	DBMS_OUTPUT.PUT_LINE('hello world');
END;

【例2】 创建存储过程,计算指定学生的总学分。

sql 复制代码
CREATE OR REPLACE PROCEDURE totalcredit
	 ( xh IN varchar2)
AS
	xf number;
BEGIN
	SELECT 总学分	
		INTO xf
		FROM XSB
		WHERE 学号=xh AND rownum=1;
	DBMS_OUTPUT.PUT_LINE(xf);
END;

注意: 在存储过程体中,不能使用SELECT语句直接查询,否则会出现编译错误。

【3】计算机某专业总学分大于50分的人数,该存储过程使用了一个输入(IN)参数和一个(OUT)参数。

2.以界面方式创建存储过程

如果要通过界面方式定义上面的存储过程count_grade,步骤如下。

(1)启动SQL Developer,选择myorcl连接的"过程"节点,右击鼠标,选择"新建过程"菜单项进入"创建 PL/SQL 过程"对话框,如图所示。

(2)在"名称"文本框中输入存储过程的名称,单击 按钮添加一个参数,在"参数"选项页的"Name"栏中输入各参数名称,在"Type"栏中选择参数的类型,在"Mode"栏中选择参数的模式,在"Default Value"栏中输入参数默认值(如果有的话)。

(3)单击"确定"按钮,在出现的"COUNT_GRADE"过程的编辑框中编写过程语句块,如图7.2所示,单击"编译以进行调试"按钮完成过程的创建。

(二)存储过程的调用

调用存储过程一般使用EXEC语句,语法格式为:

sql 复制代码
[ { EXEC | EXECUTE } ]  <过程名> 
	[ ( [<参数名> =>] <实参> | @<实参变量> [,...n]) ] [;]

说明:EXEC是EXECUTE的缩写,<参数名>为CREATE PROCUDURE中定义的参数名称。在传递参数的实参时,如果指定了变量名,该变量则用于保存OUT参数返回的值;如果省略"<参数名>=>",则后面的实参顺序要与定义时参数的顺序一致。

【例4】 调用【例1】中的存储过程proc。

sql 复制代码
EXEC proc;

//或者
BEGIN
	proc;
END;

【例5】 从XSCJ数据库的XSB表中查询某人的总学分,根据总学分写评语。

sql 复制代码
CREATE OR REPLACE PROCEDURE update_info
 ( xh in char )
AS
	xf number;
BEGIN
	SELECT 总学分 INTO xf
		FROM XSB
		WHERE 学号=xh AND ROWNUM=1;
	IF xf>50 THEN
		UPDATE XSB SET 备注= '三好学生' WHERE 学号=xh;
	END IF;
	IF xf<42 THEN
		UPDATE XSB SET 备注= '学分未修满' WHERE 学号=xh;
	END IF;
END;

执行存储过程update_info:

sql 复制代码
EXEC update_info(xh=>'151242');

【例6】 统计XSB表中男女同学的人数。

sql 复制代码
CREATE OR REPLACE PROCEDURE count_number
	( sex IN char, num OUT number )
AS
BEGIN
	IF sex= '男' THEN
		SELECT COUNT(性别) INTO num
			FROM XSB
			WHERE 性别= '男';
	ELSE
		SELECT COUNT(性别) INTO num
			FROM XSB
			WHERE 性别= '女';
	END IF;
END;

在调用过程count_number时,需要先定义OUT类型参数,如下:

sql 复制代码
DECLARE 
	girl_num number;
BEGIN
	count_number('女', girl_num);
	DBMS_OUTPUT.PUT_LINE(girl_num);
END;

(三)存储过程的修改

修改存储过程和修改视图一样,虽然也有ALTER PROCEDURE语句,但它是用于重新编译或验证现有过程的。如果要修改过程定义,仍然使用CREATE OR REPLACE PROCEDURE命令,语法格式一样。 其实,修改已有过程本质就是使用CREATE OR REPLEACE PROCEDURE重新创建一个新的过程,只要保持名字与原来的过程相同即可。 使用界面方式也可很方便地修改存储过程定义。在SQL Developer中,在"过程"节点下选择要修改的存储过程,右击鼠标,选择"编辑"菜单项,在打开的存储过程编辑窗口中修改定义后单击"编译以进行调试"按钮即可。

当某个过程不再需要时,应将其删除,以释放它占用的内存资源。 删除过程的语法格式为:

sql 复制代码
DROP PROCEDURE [<用户方案名>.] <过程名>;

【例7】 删除XSCJ数据库中的count_number存储过程。

sql 复制代码
DROP PROCEDURE count_number;

也可以使用界面方式删除存储过程,具体操作如图所示,请读者自行尝试。

二、触 发 器

触发器是被指定关联到一个表的数据对象,它不需要调用,当对一个表的特别事件出现时,它就会被激活。触发器的代码也是由SQL语句组成的,因此用在存储过程中的语句也可以用在触发器的定义中。触发器是一类特殊的存储过程,与表的关系密切,用于保护表中的数据。当有操作影响到触发器保护的数据时,触发器将自动执行。

(一)以命令方式创建触发器

1.创建DML触发器

创建DML触发器 语法格式为:

sql 复制代码
CREATE [OR REPLACE] TRIGGER [<用户方案名>.] <触发器名>
	{ BEFORE∣AFTER∣INSTEAD OF }			/*定义触发动作*/
	{ DELETE | INSERT | UPDATE [ OF <列名>[,...n] ]}		/*定义触发器种类*/
		[OR { DELETE | INSERT | UPDATE [ OF <列名>[,...n] ]}]
	ON  {<表名>∣<视图名>}           	  	 	/*在指定表或视图中建立触发器*/
	[ FOR EACH ROW [ WHEN(<条件表达式>) ] ]
	<PL/SQL语句块>

【例8】 创建一个表table1,其中只有一列a。在表上创建一个触发器,每次插入操作时,将变量str的值设为"TRIGGER IS WORKING"并显示。

创建表table1:

sql 复制代码
CREATE TABLE table1(a number);

创建INSERT触发器table1_insert:

sql 复制代码
CREATE OR REPLACE TRIGGER table1_insert
	AFTER INSERT ON table1
DECLARE 
	str char(100) :='TRIGGER IS WORKING';
BEGIN
	DBMS_OUTPUT.PUT_LINE(str);
END;

向table1中插入一行数据:

sql 复制代码
INSERT INTO table1 VALUES(10);

【例9】 在XSCJ数据库中增加一个日志表XSB_HIS,表结构和XSB表相同,用来存放从XSB表中删除的记录。创建一个触发器,当XSB表被删除一行时,把删除的记录写到XSB_HIS表中。

sql 复制代码
CREATE OR REPLACE TRIGGER del_xs
	BEFORE DELETE ON XSB FOR EACH ROW
BEGIN
	INSERT INTO XSB_HIS (学号, 姓名, 性别, 出生时间, 专业, 总学分, 备注)
		VALUES(:OLD.学号,:OLD.姓名, :OLD.性别, :OLD.出生时间, :OLD.专业, :OLD.总学分, :OLD.备注);
END;

OLD修饰访问操作完成前列的值。触发器建立后向XSB表中插入一行数据,之后查看XSB_HIS表中并没有添加了该行数据,这是因为触发器中的DML语句并没有使用提交语句提交,但触发器中不能使用COMMIT语句,所以需要定义自治事务来提交

【例10】 利用触发器在数据库XSCJ的XSB表执行插入、更新和删除三种操作后给出相应提示。

sql 复制代码
CREATE TRIGGER cue_xs
	AFTER INSERT OR UPDATE OR DELETE ON XSB FOR EACH ROW
DECLARE
	Infor char(10);
BEGIN
	IF INSERTING THEN				/*INSERT语句激活了触发器*/
		Infor:= '插入';
	ELSIF UPDATING THEN			/*UPDATE语句激活了触发器*/
		Infor:= '更新';
	ELSIF DELETING THEN			/*DELETE语句激活了触发器*/
		Infor:= '删除';
	END IF;
	DBMS_OUTPUT.PUT_LINE(Infor);
END;

说明:程序中使用条件谓词IF通过谓词INSERTING、UPDATING和DELETING分别判断是否是INSERT、UPDATE和DELETE激活了触发器。另外,在UPDATE触发器中使用UPDATING(列名)的形式来判断特定列是否被更新。

2.创建替代触发器

创建替代触发器使用INSTEAD OF关键字,一般用于对视图的DML触发。由于视图有可能由多个表进行关联而成,因而并非所有的关联都是可更新的。INSTEAD OF触发器触发时只执行触发器内部的SQL语句,而不执行激活该触发器的SQL语句。 例如,若在一个多表视图上定义了INSTEAD OF INSERT触发器,视图各列的值可能允许为空也可能不允许。若视图某列的值不允许为空,则INSERT语句必须为该列提供相应的值。

【例7.11】 在XSCJ数据库中创建视图stu_view,包含学生学号、专业、课程号、成绩。该视图依赖于表XSB和CJB,是不可更新视图。可以在视图上创建INSTEAD OF触发器,当向视图中插入数据时分别向表XSB和CJB插入数据,从而实现向视图插入数据的功能。

首先创建视图:

sql 复制代码
CREATE VIEW stu_view
AS 
SELECT XSB.学号, 专业, 课程号, 成绩
	FROM XSB, CJB
	WHERE XSB.学号=CJB.学号

创建INSTEAD OF触发器:

sql 复制代码
CREATE TRIGGER InsteadTrig
	INSTEAD OF INSERT ON stu_view FOR EACH ROW
DECLARE 
	xm char(8);
	xb char(2);
	cssj date;
BEGIN
	xm:='徐鹤';
	xb:= '男';
	cssj:= '1997-07-28';
	INSERT INTO XSB(学号, 姓名, 性别, 出生时间, 专业) 
		VALUES(:NEW.学号,xm, xb, cssj, :NEW.专业);
	INSERT INTO CJB VALUES(:NEW.学号, :NEW.课程号, :NEW.成绩);
END;

向视图插入一行数据:

sql 复制代码
INSERT INTO stu_view VALUES('151116', '计算机', '101', 85 );

查看数据是否插入:

sql 复制代码
SELECT * FROM stu_view WHERE 学号= '151116';

执行结果如图所示。

查看与视图关联的XSB表的情况:

sql 复制代码
SELECT * FROM XSB WHERE 学号= '151116';

执行结果如图所示。

3.创建系统触发器

系统触发器可以在DDL或数据库系统事件上被触发。DDL指的是数据定义语句,如CREATE、ALTER和DROP等。而数据库系统事件包括数据库服务器的启动(STARTUP)、关闭(SHUTDOWN)、出错(SERVERERROR)等。 创建系统触发器的语法格式为:

sql 复制代码
CREATE OR REPLACE TRIGGER [<用户方案名>.] <触发器名>
	{ BEFORE︱AFTER }
	{ <DDL事件>︱<数据库事件> }
	ON { DATABASE︱[用户方案名.] SCHEMA }
	<触发器的PL/SQL语句块>

【例12】 创建一个用户事件触发器,记录用户SYSTEM所删除的所有对象。 首先以用户SYSTEM身份连接数据库,创建一个存储用户信息的表:

sql 复制代码
CREATE TABLE dropped_objects
(
	object_name varchar2(30),
	object_type varchar(20),
	dropped_date date
);

创建BEFORE DROP触发器,在用户删除对象之前记录到信息表dropped_objects中。

sql 复制代码
CREATE OR REPLACE TRIGGER dropped_obj_trigger
	BEFORE DROP ON SYSTEM.SCHEMA
BEGIN
	INSERT INTO dropped_objects
		VALUES(ora_dict_obj_name, ora_dict_obj_type, SYSDATE);
END;

现在删除SYSTEM模式下的一些对象,并查询表dropped_objects:

sql 复制代码
DROP TABLE table1;
DROP TABLE table2;
SELECT * FROM dropped_objects;

以界面方式创建触发器

触发器也可以利用SQL Developer的界面方式创建。

(1)选择myorcl连接的"触发器"节点,右击鼠标,选择"新建触发器"菜单项,进入"创建触发器"窗口,如图所示。

(2)在"名称"栏中输入触发器名称,在"触发器"选项卡中的"触发器类型"下拉列表中选择触发依据,有"Table""View""SCHEMA"和"Database"等选项。例如,如果是在表中创建触发器,则这里就选择"TABLE"。可以在"表名"栏中选择触发器所在的表,选中"早于"或"晚于"选项对应BEFORE和AFTER关键字,勾选"插入"、"删除"和"更新"复选框对应触发事件,完成后单击"确定"按钮。

(3)在出现的触发器代码编辑框中编写触发器定义中的PL/SQL语句,完成后单击工具栏的"编译以进行调试"按钮完成触发器的创建,如图所示。

(二)触发器的删除

1.以命令方式删除触发器

删除触发器使用DROP TRIGGER语句,语法格式为:

sql 复制代码
DROP TRIGGER [<用户方案名>.] <触发器名>

【例13】 删除触发器del_xs。

sql 复制代码
DROP TRIGGER del_xs;

2.以界面方式删除触发器

在"触发器"节点中选择要删除的触发器,右击鼠标,选择"删除触发器"菜单项,在弹出的"删除触发器"对话框中单击"应用"按钮即可。操作如图所示。

最后,感谢大家的观看

相关推荐
sdaxue.com1 小时前
帝国CMS:如何去掉帝国CMS登录界面的认证码登录
数据库·github·网站·帝国cms·认证码
o(╥﹏╥)2 小时前
linux(ubuntu )卡死怎么强制重启
linux·数据库·ubuntu·系统安全
阿里嘎多学长2 小时前
docker怎么部署高斯数据库
运维·数据库·docker·容器
Yuan_o_2 小时前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端
Sunyanhui12 小时前
牛客网 SQL36查找后排序
数据库·sql·mysql
老王笔记3 小时前
MHA binlog server
数据库·mysql
lovelin+v175030409663 小时前
安全性升级:API接口在零信任架构下的安全防护策略
大数据·数据库·人工智能·爬虫·数据分析
DT辰白4 小时前
基于Redis的网关鉴权方案与性能优化
数据库·redis·缓存
2401_871213304 小时前
mysql高阶语句
数据库·mysql