第四章:触发器   触发器类似于过程、函数,因为它们都是拥有说明部分、语句执行部分和异常处理部分的有名的PL/SQL块。与包类似,触发器必须存储在数据库中,并且不能被块进行本地化说明。但是,对于过程而言,可以从另一个块中通过过程调用显式地执行一个过程,同时在调用时可以传递参数。对于触发器而言,当触发事件发生时就会显式地执行该触发器,并且触发器不接受参数。

Slides:



Advertisements
Similar presentations
Oracle. 数据操纵语言  数据操纵语言用于检索、插入和修改数据  数据操纵语言是最常见的 SQL 命令  数据操纵语言命令包括:  SELECT  INSERT  UPDATE  DELETE.
Advertisements

第二章 简单的 SQL 语句. 本章要点  创建一个简单的表  SQL 语句介绍  最简单的查询语句 select  带有限制条件的查询  查询结果的排序显示.
1 第 5 章 SQL 语句基础 在 Oracle 数据库中,为了方便管理用户所创建的 数据库对象,引入了模式的概念,这样用户所创建的 数据库对象就都属于该用户模式。对于一般的用户而 言,数据库中的数据是以表、视图行等方式存储的( 表和视图就是最基本的用户模式对象),用户只需要 根据自己的需求查询数据库,然后由数据库根据请求.
数据库完整性 第 10 章 完整性约束条件 完整性控制 Oracle 的完整性. 什么是数据库的完整性  数据的正确性和相容性  防止不合语义的数据进入数据库 例 : 学生的年龄必须是整数,取值范围为 ; 学生的性别只能是男或女; 学生的学号一定是唯一的; 学生所在的系必须是学校开设的系。
2010 年 6 月课件制作人:王亚楠 1 模块 2 项目开发概论 教学课件 年 6 月课件制作人:王亚楠 2 目录 目标 了解:数据库技术的基本概念与结构 理解:数据模型的分类与结构组成 掌握:关系数据库及 SQL 的基本理论 知识 掌握:数据库设计的方法与步骤 内容 2.1 数据库技术基础.
MySQL 基础技能与原理 —— 基础技能 MySQL DBA Team 彭立勋( )
2011/11,12 南台資管 吳昭儀. 1. 使用者介面 (User Interface)  使用者操作畫面的安排  Textbox, ComboBox, ListBox, CheckList, … 2. 流程控制 (Process Control)  使用者輸入資料檢查  計算  資料輸出.
Data type P64 ‘’ 转义字符 P67 P68 EXE,选出某个教师的学生中最新的一 个,要姓名, ID (,LIMIT ) EXISTS,NOT EXISTS P409 Q,EXISTS 和 in 的区别( 1000 ,查询结果)
Java 技术与应用 数据库应用 ( 第 14 章 ) 西安交大 卫颜俊 2008 年 12 月 电子信箱: QQ: 网站 : /java.
第 7 章 数据库 1. Overview  数据库概述  数据库管理系统  数据库的体系结构和数据库模型  SQL 语言  数据库技术  构建数据库系统 2.
《 ORACLE 》 计算机技术与软件工程学院 胡斌 学习情境 6 系统安全管理( 8 学时) 按照系统的职能范围不同,可将Oracle的安全体系 结构分成三个部分; (1)数据库内部的管理:主要包括用户标识/口令 ;角色与权限等。 (2)资源管理:主要通过系统概要文件限制连接 会话等。 ( 3.
第八单元 数据库MySQL应用基础 MySQL数据库应用基础 MySQ数据库操作使用 Mysql管理工具 第25章 数据库的增加/删除操作
關聯查詢.
十一 ASP对数据库的访问.
第2章 SQL语言初步 2.1 SQL的基本概念 2.2 基本表、索引的创建、删除和修改操作 2.3 SQL的查询语句——SELECT
第2讲 Transact-SQL语言.
第5章 索引及视图操作 数据库原理应用与实践 SQL SERver2014(第2版) 主编 贾铁军 科学出版社 编著 陈国秦 万程 邢一鸣
第14章 預存程序 14-1 預存程序的基礎 14-2 建立與執行預存程序 14-3 預存程序的參數傳遞 14-4 預存程序的傳回值
第4章 关系数据库标准语言SQL 4.1 SQL语言概述 4.2 SQL数据查询功能 4.3 SQL数据操作功能 4.4 SQL数据定义功能.
資料庫 (Database) SQL Server 2008實作
第3章 SQL的基础知识 数据库管理及应用 3.1 SQL简介 3.2 SQL的数据模型 3.3 标识符 3.4 使用SQL语句管理数据库
数据库概述 简而言之,数据库(DataBase)就是一个存储数据的仓库。为了方便数据的存储和管理,它将数据按照特定的规律存储在磁盘上。通过数据库管理系统,可以有效的组织和管理存储在数据库中的数据。如今,已经存在了Oracle、SQL Server、MySQL等诸多优秀的数据库。在这一章中将讲解的内容包括。
数据库原理及设计 --作业.
Oracle数据库 Oracle 子程序.
PL/SQL程序设计 过程, 函数 Trigger 对象关系数据库技术.
数据库应用与程序设计.
主机DB2数据库应用与编程 任课老师:王湖南 四川大学计算机(软件)学院.
第五讲 利用视图进行查询优化.
關聯式資料庫.
Oracle数据库入门.
第十五章 常見的資料庫管理系統 目的 Oracle 微軟SQL Server 微軟Access MySQL Oracle 應用伺服器
数据库技术 第十章 数据库完整性 中国科学技术大学网络学院 阚卫华.
ORACLE 第五讲 PL/SQL编程基础.
第 8 章 資料的 新增、修改與刪除.
課程名稱:資料庫系統 授課老師:李春雄 博士
Chap 10 SQL定義、操作與控制指令.
第 11 章 建立檢視表.
第 7 章 建立資料表與 資料庫圖表.
資料庫安全 (Database Security)
第16讲 数据库系统的增强安全性 第7章:数据库系统的增强安全性.
Transact-SQL 語言設計教學.
第8章 数据库的安全和完整性约束 数据库的破坏一般来自: 1.系统故障; 2.并发所引起的数据不一致; 3.人为的破坏;
第 16 章 觸發程序.
課程名稱:資料庫系統 授課老師:李春雄 博士
課程名稱:資料庫系統 授課老師:李春雄 博士
第7章 ADO.NET操作SQL Server数据库
第3章 MySQL教學範本 主從式資料庫系統 - CH3.
建立/修改/刪除資料表 建立資料表 使用Enterprise Manager工具
第三章:包   包(package)是一个可以将相关对象存储在一起的PL/SQL结构。包包含了两个分离的部件------包说明(specification)和包主体(body)。每个部件都单独被存储在数据字典中。包只能存储在数据库中,不能是本地的。除了可以将相关对象作为一组存在一起以外,包也是十分有用的,因为它们在依赖性方面的限制是比较小的。也有许多性能上的优点。
SQL SERVER 一些经典语句 1.
实验4:PL-SQL编程 1.实验目的 2.实验原理 PL/SQL是一种过程化语言,属于第三代语言,本实验在与熟悉使用PL/SQL编程.
第四讲 数据库对象(视图、序列、同义词、索引)
Ch4.SQL Server 2005資料庫組成員元件介紹
iRepor报表设计基础 IReport安装 普通实体报表 数据结果集报表 工作流主从报表 饼状图报表 柱状图,曲线图报表 条形码报表
数据库应用技术 SQL Server 2005.
第20章 MySQL数据库.
数据库技术与应用.
第四章 PL/SQL控制结构 If-then:如果条件为true,则执行一行或多行代码,如果条件为假,转到end if之后。
ORACLE 第九讲 触发器.
4.2 视图 (1) 视图是一个虚拟表,其内容来自对表查询的基础上。
CS, ZJU 4/18/2019 Chapter 7 数据库.
3.2 Mysql 命令行 1 查看数据库 SHOW DATABASES; 2 创建一个数据库test1 CREATE DATABASE test1; 3 选择你所创建的数据库 USE test1; (按回车键出现Database changed 时说明操作成功!) 4 查看现在的数据库中存在什么表.
SQL查询语句 蔡海洋.
第三章 SQL Server数据管理.
第 7 章 建立資料表與資料庫圖表.
第4章 表的创建与维护 4.1 数据类型 4.2 数据完整性约束 4.3 创建数据表 4.4 修改数据表 4.5 删除数据表.
Oracle Database 10g基础教程 清华大学出版社
11 檢視表的建立 11-1 檢視表的基礎 11-2 建立檢視表 11-3 修改與刪除檢視表 11-4 編輯檢視表的內容.
Principle and Technology of Database
第4章 数据查询.
Presentation transcript:

第四章:触发器   触发器类似于过程、函数,因为它们都是拥有说明部分、语句执行部分和异常处理部分的有名的PL/SQL块。与包类似,触发器必须存储在数据库中,并且不能被块进行本地化说明。但是,对于过程而言,可以从另一个块中通过过程调用显式地执行一个过程,同时在调用时可以传递参数。对于触发器而言,当触发事件发生时就会显式地执行该触发器,并且触发器不接受参数。

触发事件是在数据库表上执行的DML(INSERT、UPDATE、DELETE)操作。使用触发器,可以做许多事情,包括: ● 维护不可能在表创建时通过说明性约束进行的复杂 的完整性约束限制。 ● 通过记录所进行的修改以及谁进行了修改来审计表 中的信息。 ●当表被修改的时候,自动给需要执行操作的程序发信 号。

1.触发器概念及组成   制作一个数据库触发器,目的是在某个表上执行特定的数据维护操作时,隐含地执行一个PL/SQL块。

例子:制作一个数据库触发器。记录下那些超过其工种工 资范围的工资值(但不禁止这种操作)   CREATE TRIGGER check_sal BEFORE INSERT OR UPDATE OF sal,job ON emp FOR EACH ROW WHEN(new.job<> ‘PRESIDENT’) DECLAER v_minsal sal_guide.minsal%TYPE; v_maxsal sal_guide.maxsal%TYPE; e_sal_out_of_range EXCEPTION;

BEGIN SELECT minsal,maxsal INTO v_minsal,v_maxsal FROM sal_guide WHERE job = :new. job; IF :new.sal<v_minsal OR :new:sal>v_maxsal THEN RAISE e_sal_out_of_range; END IF; EXCEPTION WHEN e_sal_out_of_range THEN INSERT INTO audit_message(line_nr,line) VALUES(l,‘Salary’|| TO_CHAR(:new.sal)|| ‘is out of range for employee’||TO_CHAR(:new.empno)); END;

★ 关联触发器   把一个数据库触发器的动作与另一个触发器联系起来,使之触发这另一个触发器。

例子——制作相关联的触发器。在一个全局变量中统计 审计信息的总数   CREATE TRIGGER count_audit_message BEFORE INSERT ON audit_message BEGIN emp_package.v_total_audit:=emp_package.v_total_audit+1; END;   注释: ·参数MAXOPENCURSORS限制在一个数据库中可用 的关联触发器的个数,其缺省值为32。

★ 写触发器的源代码之前,先确定好其触发时间、触发事件及触发器的类型。 内容 描述 可能值 触发时间 与触发事件的时间次序 ● BEFORE   内容 描述 可能值 触发时间 与触发事件的时间次序 ● BEFORE ● AFTER  触发事件 触发触发器的数据操作 ● INSERT 事件类型 ● UPDATE ● DELETE  触发器类型 触发器体被执行的次数 ● Statement ● ROW  触发器体 该触发器将要执行的动作 完整的 PL/ SQL块  

  通过对触发器各部分的不同组合,对同一表最多可以创建12个触发器。

★ 数据库触发器与存储过程之间的关键性区别。   数据库触发器 存储过程 __________________________________________________当某类数据操纵发生 从一个应用或过程中显式地调 时隐式地调用 用 在触发器体内禁止使用 在过程体内可以使用所有 PL/COMMIT,BOLLBACK, SQL块 中能使用的 SQL语句 SAVEPOINT语句

注释:   ● 不但禁止在触发器内用 COMMIT,ROLLBACK和SAVEPOINT语句,而且禁止触发器直接或间接地调用那些含有COMMIT,ROLLBACK和SAVEPOINT语句的存储过程。

★ 数据库触发器和Forms触发器的区别   数据库触发器 Forms触发器 可被任何数据库工具或 只能在特定的Forms应用中执行 应用调用、执行 常常被一个 SQL数据 触发事件可能是从一个域到另一个 操纵语句触发 域、或按下了一个功能键、或许多其 它的事件或动作 分为语句级触发器和 不为分语句级触发器和行级触发器 行级触发器 发生错误时,返回被触 发生错误时,锁住游标,并回退整个 发的语句 事务 独立于Forms触发器触发 独立于数据库触发器触发

★ 行级触发器与语句级触发器的区别   根据进行一个操作时触发器的触发次数,来决定是创建一个语句级触发器,还是创建一个行级触发器。 ● 注意当某操作只影响到表中的一行数据时,语句级触发器与行级触发器的效果相同。

例子:下面的语句对语句级触发器和行级触发器效果一样   SQL> INSERT INTO DEPT(deptno,dname) VALUES(50,‘EDUCATION’);   SQL> UPnATE DEPT SET LOC=‘MAUI’ WHERE DEPTNO=50;   SQL> DELETE FROM DEPT WHERE DEPTNO=50;  

●当触发事件影响数据库的多行时,语句级触发器只触发一次,而行级触发器则每一行被触发一次。  

例子----下列语句的行级触发器与语句级触发器效果不同   SQL>INSERT INTO EMP(empno,ename) 2 SELECT empno,ename 3 FROM EMP_BACKUP;   SQL> UPDATE DEPT 2 SET SAL= SAL*1.1 3 WHERE DEPTNO=10;   SQL> DELETE FROM EMP 2 WHERE DEPTNO=10;  

注释:   ● 在一个预编译应用中进行数组处理时,行级触发器与语句级触发器的结果不同。

2.创建触发器 ⑴ 开发触发器的步骤 ●用系统编辑器或字处理软件写一个含有 CREATE TRIGGER语句的脚本文件。   ⑴ 开发触发器的步骤 ●用系统编辑器或字处理软件写一个含有 CREATE TRIGGER语句的脚本文件。 ●在写 CREATE TRIGGER语句时,充分考虑运行时出 错的处理。 ●在 SQL*Plus或 SVRMGR中运行脚本文件,将触发器的 源代码编译成编译代码p_code,并把源代码存储到数据 库中。编译代码p_code不存储在数据库中。 ●调试编译错误。 ●在 ORACLE环境中测试开发的触发器(用INSERT、 UPDATE、DELETE语句对表进行操作)。 ●在运行期间调试触发器的逻辑错误。

⑵ 语句级触发器 用 CREATE TRIGGBR语句创建一个语句级触发器,该触发器在一个数据操作语句发生时只触发一次。   用 CREATE TRIGGBR语句创建一个语句级触发器,该触发器在一个数据操作语句发生时只触发一次。 语法——创建一个语句级触发器 CREATE [OR REPLACE ] TRIGGER trigger_name {BEFORE|AFTER} event1 [OR event2...] ON table_name PL/SQL block

其中: trigger name 触发器名 timing 指明触发事件触发的时间顺序: ● BEFORE ● AFTER event 指明触发事件的数据操纵类型 ● INSERT ● UPDATE ● DELETE table name 标明与该触发器相关联的表名 pl/sql block 触发器体,指明该触发器将执行的操 作

注释: ● 当触发器已经存在时,用 REPLACE选项。 ● 用 OF关键字指明 UPDATE事件修改的特定的列。   ● 当触发器已经存在时,用 REPLACE选项。 ● 用 OF关键字指明 UPDATE事件修改的特定的列。 ● PL/SQL块以 DBCLARE或BEGIN开头,以 END结 束。

例子1——创建一个 BEFORE型语句级触发器。限制一周内往 EMP表插入数据的时间   CREATE OR REPLACE TRIGGER secure_emp BEFORE INSERT ON emp DECLARE v_dummy VARCHAR2(l); BEGIN IF(TO_CHAR(sysdate,‘DY’) IN(‘SAT’,‘SUN’)) OR(TO_CHAR(sysdate,‘HH24’) NOT BETWEEN 8 AND 18) THEN RAISE_APPLICATION_ERROR(-20500, ‘YOU may only insert into EMP during normal hours.’); END IF; END;

例子2:创建一个 AFTER型语句级触发器。以在事件完成后对触发事件进行审计,或者执行计算。   假定用户有一个自定义的审计表,其中包含所有用户和他们进行数据操纵操作的计数信息。当一个用户对EMP表中的薪水进行修改时,利用审计表来保证某用户薪水的变化值不超过其允许值。  

CREATE TRIGGER check_sal_count AFTER UPDATE OF sal ON emp DECLARE v_sal_changes NUMBER; v_max_changes NUMBER; BEGIN SELECT upd, max_upd INTO v_sal_changes,v_max_changes FROM audit_table  

注释: WHERE user_name=user AND table_name=‘EMP’ AND column_name=‘SAL’; IF v_sal_changes>v_max_sal_changes THEN RAISE_APPLICATION_ERROR(-20501, ‘YOU may only make a maximum of’|| TO_CHAR(v_max_changes)||‘to the SAL olumn.’); END IF; END; 注释:   ● 如果某触发器没必要在触发事件发生后触发,创建 BEFORE型语句级触发器。

例子:创建一个包含多个触发事件的触发器。在触发器体中使用条件语句,指明 INSERTING,UPDATING及 DELETING,从而把多种触发事件组成一个触发器。   对前面的例子进行扩展,使其不但限制某周内插入数据的时间,还限制进行数据修改和删除的时间。

CREATE TRIGGER secure_emp BEFORE DELETE OR INSERT OR UPDATE ON emp DECIARE v_dummy VARCHAR2(1); BEGIN IF (TO_CHAR(sysdate,‘DY’ IN (‘SAT’,‘SHN’)) OR(TO_NUMBER(sysdate,‘HH24’) NOT BETWEEN 8 AND18) THEN IF DELETING THEN RAISE_APPLICATION_ERROR(一20502, ‘You may only delete from EMP during normal hours.’) ; ELSIF INSERTING THEN RAISE_APPLICATION_ERROR(一20500, ‘You may only insert into EMP during mormal hours.’) ;

ELSIF UPDATING(‘SAL’) THEN RAISE_APPLICATION_ERROR(一20503, ‘You may only update SAL column during normal hours.’) ; ELSE RAISE_APPLICATION_ERROR(一20504, ‘You may only update EMP table during normal hours.’) ; END IF; END;

⑶ 行级触发器   通过在 CREATE TRIGGER语句中指定 FOR EACH ROW子句创建一个行级触发器,使其在受到触发事件影响的每一行上都被触发。 ★ 语法:创建一个行级触发器 CREATE [OR REPLACE] TRIGGER trigger_name {BEFORE|AFTER} trigger_event1 [OR trigger_event2...] ON table_name [FOR EACH ROW [WHEN restricting_condition]] PL/SQL block; 其中: restricting condition为指定的条件,以确定触发器体是否被执行。

例子:创建一个行级触发器。记录下每个用户对数据库的表进行数据操纵的次数   CREATE TRIGGER audit_emp AFTER DELETE OR INSERT OR UPDATE ON emo FOR EACH ROW BEGIN IF DELETINC THEN UPDATE audit_table SET del= del+l WHERE user_name=user AND table_name=‘EMP’ AND colun_name IS NULL;

ELSIF INSERTING THEN UPDATE audit_table SET ins=ins+l WHERE user_name=user AND table_name=‘EMP’ AND column_name IS NULL; ELSIF UPDATING(sal) THEN SET upd=upd+l WHERE user_name=user . AND column name=‘SAL’;

注释: EISE UPDATE audit_table SET upd=upd+1 WHERE user_name= user AND table_name=‘EMP’ AND column_name IS NULL; END IF; END; 注释:   ● 如果一个触发器不必在触发事件前触发,请创建 AFTER型触发器(不要创建 BEFORE型)

★ 行级触发器的标识符   在行级触发器中,在列名前加上 OLD标识符标识该列变化前的值,加上 NEW标识符标识变化后的值。 数据操作 旧值 新值 Insert NULL 插入的值 Update 修改前的值 修改后的值 Delete 删除前的值 NULL

注释: ● 在 BEFORE型行级触发器和 AFTER型行级触发器 中使用这些标识符。 ● 在语句级触发器中不要使用这些标识符。   ● 在 BEFORE型行级触发器和 AFTER型行级触发器 中使用这些标识符。 ● 在语句级触发器中不要使用这些标识符。 ●在SQL语句或 PL/SQL语句中,在这些标识符前加 冒号(:)来引用它们。

例子:在行级触发器中获取某列的新值和旧值。为 EMP表中的所有数据保留一个历史档案(审计)   CREATE TRIGGER audit_emp_values AFTER DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW BEGIN INSERT INTO audit_emp_values(user_name,timestamp, empno,old_ename,new_ename,old_job,new_job, old_mgr, new_mgr, old_sal,new_sal) VALUES(USER,SYSDATE,:old.empno,:old.ename, : new.ename,:old.jOb,:new.job,:old.mgr, :new.mgr,: old.sal,:new. sal); END;  

详细的用户审计表 用 WHEN子句来保证,当某些行满足一定条件时,在该行上行级触发器才被触发。

注释: 例子:在行级触发器限制其触发。自动计算销售员的奖金 CREATE TRIGGER derive_comm   CREATE TRIGGER derive_comm BEFORE INSERT OR UPDATE OF sal ON emp FOR EACH ROW WHEN (new.job=‘SALESMAN’) BEGIN :new.comm := :old. comm * (:new. sal/ :old. sal); END; 注释:   ● 在 WHEN子句中,标识符前不加冒号(:) ● 在语句级触发器中不要使用 WHEN子句。

⑷ 语句级和行级触发器的作用 根据不同的情况创建语句级触发器和行级触发器。 ★ 利用语句级触发器实现下列例程 ● 防止非法的数据操纵   根据不同的情况创建语句级触发器和行级触发器。 ★ 利用语句级触发器实现下列例程 ● 防止非法的数据操纵 ● 审计数据操作 ● 控制数据操作的安全性 ● 初始化和重新给全局变量及标志赋值

★ 利用行级触发器实现下列例程   ● 防止行上的非法数据 ● 审计受数据操纵影响的行的信息及其值的信息 ● 控制数据完整性及参考完整性 ● 用全局变量和标志控制数据操作 ● 复制表 ● 透明地计算获得的值 ● 修改数据并隐式地执行函数

⑸ INSTEAD OF 触发器   INSTEAD OF 触发器可用来操纵对视图的插入、修改、删除。当一个视图是根据几个表创建的时候,INSTEAD OF 触发器就特别有用。INSTEAD OF 触发器的工作方式与行级、语句级触发器是类似的。在下面的代码中,在EMPLOYEE_NAMES视图上创建了两个触发器。 第一个触发器将直接插入雇员表。它还将INSERT 语句中的雇员标识的值废掉。而在为了生成雇员标识号而定义的序列生成器中插入下一个值。

Create or replace trigger employee_names_trigger Instead of insert on employee_names Begin Insert into employee values (employee_sequence.nextval,:new.f_name,:new.l_name ,null,null,null,null); end; /  

第二个触发器生成一条用户定义的报错语句,它责备用户企图通过这个视图删除雇员。虽然经常允许对视图处理这类操作,但是能产生一条比通常的‘ORA-01031:没有足够权限’说明得更清楚的报错消息总是件好事。   Create or replace trigger employee_names_trigger_delete Instead of delete on employee_names Begin Raise_application_error(-20002,’you may not delete Employee through this views!’); End; /

3.触发器的管理 管理触发器的命令与管理过程的命令相似。 任务 命令   任务 命令 ___________________________________________________ 创建一个新的触发器 CREATE TRIGGER 修改一个已有的触发器 CREATE OR REPLACE TRIGGER 删除触发器 DROP TRIGGER 与过程不同的是,当一个触发器不再适宜被触发时,可以使其处于无效状态。

注释: 语法——使一个数据库触发器无效 ALTER TRIGGER—— trigger name—DISABLE   ALTER TRIGGER—— trigger name—DISABLE   语法:使一个数据库触发器重新变为有效 ALTER TRIGGER——trigger name—ENABLE 注释:   ● 当触发器刚创建时,它被自动置为有效。 ● 为了改善性能,以及在大量装载数据时(例如使用 SQL* Loader)避 免进行数据的完整性校验,可以使 数据库触发器暂时无效。 ●当发生网络连接故障、磁盘损坏,数据文件脱机或 表空间脱机,从而导致触发器中涉及到的实体不能 再被访问时,应使触发器失效。  

★ 存储触发器和存储一个过程之间的一个重要区别 存储一个触发器   ● 在一个文本文件中写入 CREATE TRIGGER语句。 ● 运行该文本文件,以运行 CREATE TRIGGER语句。 · 如果触发器编译成功,则数据库只将其源代码存入 库中,编译代码不进行存储。 · 当发生编译错误时,ORACLE以交互方式将触发器 的语法错误通知用户,但这些错误信息不进行存储。 ● 当触发器触发时,必须首先重新编译。

存储一个过程   ● 写一个含 CREATE PROCEDURE语句的文本文 件。 ● 运行该文件。 · 如果过程编译成功,其源代码和编译代码都 被存人数据库中。 · 如果出现编译错误,则这些语法错误信息将 被存人数据字典中。 ● 当运行一个过程时,通常不需要对其重新编译。 ● 如果需要,用手动方式重新编译该过程。

★ 管理触发器的命令与管理过程的命令稍有差别。

注释: ● 虽然触发器中可以引用另外的数据库实体,但它们之 间并没有依赖关系,因为触发器在每次触发前都要重新 编译。   ● 虽然触发器中可以引用另外的数据库实体,但它们之 间并没有依赖关系,因为触发器在每次触发前都要重新 编译。 ● 无法手工编译触发器。

查看数据字典中 USER_TRIGGERS视图,可以获取合法触发器的源代码。下面是该视图的结构。 列 列描述 NAME 触发器名   TYPE 触发时间(BEFORE或AFTER)以及触发类型 (语句级或行级) TRIGGERING_ 触发事件的语句类型STATEMENT (INSERT、 UPDATE或 DELETE) TABLE_OWNER 与该触发器相关联的表的拥有用户名

注释: WHEN 限制触发条件 ENABLED 触发器的状态(ENABLED或 DISABLED)   ENABLED 触发器的状态(ENABLED或 DISABLED) TRIGGER_BODY 完整的 PL/SQL块文本 注释: ● 用户还可以查看数据字典中的 DBA_TRIGGERS视图和 ALL_TRIGGERS视图,你会发现这两个视图除了上面 的列外,还有一个新列 OWNER,标明了触发器的拥 有者。

用 SELECT查看触发器的文档信息。 例子:查看 DERIVE_COMM触发器的文档。 TRIGGER_BODY     例子:查看 DERIVE_COMM触发器的文档。   SSQL> SELECT trigger_body FROM user_triggers WHERE name=‘DERIVE_COMM’;   TRIGGER_BODY ----------------------------------------------------- BEGIN :new.comm := :old. Comm*(:new.sal/:old. sal); END;

注释: ★ 测试触发器的实例 用多种事件分别对触发器进行测试,以确保触发器的正确运行 ● 用各种触发事件和一个非触发事件对触发器进行测试   用多种事件分别对触发器进行测试,以确保触发器的正确运行 ● 用各种触发事件和一个非触发事件对触发器进行测试 ● 用满足 WHEN条件的实例进行测试。 ● 用直接的数据操作以及从过程中的间接数据操作进行测试。 ● 观察触发器依赖于其它触发器时的结果。 ● 观察当别的触发器依赖于该触发器时的结果。 注释:   ● 利用 DBMS_OUTPUT包进行调试

例:制作一个 SQL*Plus批文件,测试 DERIVE_COMM触发器。 ACCEPT p_empno PROMPT ‘please enter the new employee number:’ ACCEPT p_ename PROMPT ‘Please enter the new employee name:’ ACCEPT p_job PROMPT ‘Please enter the new employee job :’ ACCEPT p_mgr PROMPT ‘PIease enter the new manager number:’ ACCEPT p_hiredate PROMPT ‘PIease enter the new hiredate:’ ACCEPT p_sal PROMPT ‘please enter the new salary:’ ACCEPT p_deptno PROMPT ‘Please enter the new department   INSERT INTO emp(empno,ename,job ,mgr,hiredate,sal,deptno) VALUES(&p_empno,‘&p_ename’,‘&p_job’,&p_mgr, ‘&p_hiredate’, &p_sal,&p_deptno);

ACCEPT p_empno PROMPT ‘please enter the old employee number:’ ACCEPT p_ename PROMPT ‘PIease enter the new employee name:’ ACCEPT p_jOb PROMPT ‘Please enter the new employee job:’ ACCEP7 p_mgr PROMPT ‘Please enter the new manager number:’ ACCEPT p_hiredate PROMPT ‘Please enter the new hiredate:’ ACCEPT p_sal PROMPT ‘please enter the new salary:’ ACCEPT p_deptno PROMPT ‘Please enter the new department number:’   UPDATE EMP SET ename‘&p_empno’, job = ‘&p_job ’, mgr=&p_mgr, hiredate=‘&p_hiredate’, sal=&p_sal, deptno= &p_deptno WHERE empno=&p_empno;

4.在触发器中进行的数据操作 ⑴ 修改没有关联的表的数据

例子:修改一个与触发器没有相联的表。   为 EMP表中的所有数据做一个历史记录 CREATE TRIGGER audit_emp_values AFTER DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW BEGIN INSERT INTO emp_audit(user_name, timestamp, empno,old_ename,new_ename,old_job,new_job, old_mgr,new_mgr,old_sal,new_sal)

VALUES(USER,SYSDATE,:Old.empno,:old.ename, :new.ename,:Old.jOb,:new.job,:old.mgr, :new.mgr,:old.sal,: new. sal);. END;

WHERE ename=:‘SCOTT’; SQL> UPDATE emp SET job=‘PRESIDENT’ WHERE ename=:‘SCOTT’;     注释: ● 对与触发器没有相联的表的修改没有限制。

⑵ 修改被触发表的不同列数据

例子:修改被触发的表。自动计算销售人员的奖金。 CREATE TRIGGER derive_comm BEFORE INSERT OR UPDATE OF sal ON emp FOR EACH ROW WHEN (new.job=‘SALESMAN’) BEGIN :new.comm :=:old.comm*(:new.sal/:old.sa1); END; SQL> UPDATE KMP SET sal=1500 WHERE ename=‘MARTIN’;

注释: ● 只有在 BEFORE型的行级触发器中,允许 NEW标识符 出现在赋值语句的左边。   ● 只有在 BEFORE型的行级触发器中,允许 NEW标识符 出现在赋值语句的左边。 ● 在 AFTER型的行级触发器中和语句级触发手中,NEW 标识符都不允许出现在赋值语句的左边。 ● 单独的列名,或者加上了 OLD标识符的列名,绝对禁 止出现在赋值语句的左边。

⑶ 修改被触发表的同一列数据   例子——修改被触发表的同一列数据。给公司雇员加薪,最大增加量为10%

CREATE TRIGGER derive_sal BEFORE INSERT OR UPDATE OF sal ON emo FOR EACH ROW BEGIN :new.sal:=least(:new.sal, :old.sal* 1.1); END; SQL> UPDATE EMP SET sal=1500 WHERE ename=‘MARTIN’;

⑷ 修改有约束关系的关联表中的非主键列

例子——修改一个有约束关系的相关联表的非主键列数据。将部门名附到雇员名之后,送入 ENAME列。   CREATE TRIGGER append_dname AFTER INSERT OR UPDATE OF dname ON dept FOR EACH ROW BEGIN UPDATE emp SET emp.ename=emp.ename||‘-’||:new.dname WHERE emp.deptno= :new.deptno; END;

SQL> UPDATE DEPT SET dname=‘FINANCES’ WHERE dname=‘ACCOUNTING’; 注释:   ● 关联表是指通过参考完整性的约束声明,由被触发基表间接或直接参考的基表。

⑸ 不允许修改有约束关系的关联表中的主键列

例子——一个修改关联表主键列的失败的实例。 当父表(DEPT表)中的 DEPTNO列发生变化时,导致子表(EMP表)的相关行的数据发生变动。(该例子将导致一个运行错)

⑹ 读取一个没有变化的表的数据

例子——从一个没有变化的表中读取数据 强行在雇员的薪水和其工作之间制作一个复杂的完整性限制,使其薪水不能超出其工作所允许的薪水范围。

⑺ 不允许从一个变化的表中读取数据 例子——一个失败的从变化表中读取数据的实例 把薪水限制在目前的最低薪水与最高薪水之间。(下面的例子将出现一个运行错)

注释: ● 变化表是指直接或间接地受触发事件影响的表。 ● 与触发器发生联结的表本身是一个变化表。 ● 通过 DELETE CASCADE完整性约束与被触发表产生联系的表是变化表

★ 在触发器中进行数据操作总结 利用触发器读取或写入数据时,必须满足两个原则: ● 不要修改相关表的主关键字、外部关键字以及唯一性关键字所在的列。 ● 不要从变化表中读取数据。

在应用程序中创建数据库触发器,可以大大增强 ORACLE系统的性能,完成一些 ORACLE系统服务不能完成的功能。 5.触发器的应用 在应用程序中创建数据库触发器,可以大大增强 ORACLE系统的性能,完成一些 ORACLE系统服务不能完成的功能。

⑴ 安全性 ★ 在系统服务中控制实体的安全性。 在 ORACLE中创建用户和角色,通过用户的标识完成对表中数据进行操作的安全性管理。 ● 只有基于用户联结到数据库时提供的用户名的权限 ● 确定对表、视图、同义词、序列生成器的访问。 ● 确定查询、数据维护及数据定义权限。

例子——在系统服务进程中进行安全性控制。 限制用户对 EMP表的访问,使某些用户拥有访问它的权限。 SQL> GRANT CLERK TO JOE; SQL> GRANT SELECT,INSERT,UPDATE,DELETE ON EMP TO CLERK;

★ 用触发器控制实体的安全性 ● 将权限基于各种数据库的值,如时间、星期等。 ● 只决定访问表的权限。 ● 只决定数据操纵权限。 例子——在一个触发器中控制数据的安全性。限制只允许在某周的特定时间内进行数据操作。

⑵ 审计 ★ 通过系统服务进行审计 ● 可审计查询,数据操纵及数据定义语句。 ● 把审计情况写入集中的审计表中。   ★ 通过系统服务进行审计 ● 可审计查询,数据操纵及数据定义语句。 ● 把审计情况写入集中的审计表中。 ● 在每次启动时或每次访问时在审计表中增加新 的一行。 ● 捕获成功和失败的操作。 ● 动态地设置(ENABLE和 DISABLE)。

例子——利用系统服务进行审计。审计EMP表上的所有数据操作。 SQL> AUDIT INSERT,UPDATE,DELETE ON emp BY ACCESS WHENEVER SUCCESSFUL;

● 在每次启动或访问时往审计表中增加新的行。 ● 只审计成功的操作。 ● 动态设置审计标志。 ★ 在触发器中进行审计   ● 只审计数据操纵语句。 ● 将审计情况写入用户的审计表。 ● 在每次启动或访问时往审计表中增加新的行。 ● 只审计成功的操作。 ● 动态设置审计标志。 例子:——在触发器中进行审计。审计EMP表上所有成功的数据操作的数据值。

AFTER DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW BEGIN CREATE TRIGGEB audit_emp_values AFTER DELETE OR INSERT OR UPDATE ON emp FOR EACH ROW BEGIN IF audit_emp_package.v_reason IS NULL THEN RAISE_APPLICATION_ERROR(-20059,‘Specify a reason for the data operation with the procedure SET_REASON before proceeding.’) ; ELSE INSERT INTO audit_emp_values(user_name,timestamp,empno, old_ename,new_ename,old_job,new_job,old_mgr, new_mgr,old_sal,new_sal, comments) VALUES(user, sysdate, :old.empno,:old.ename, :new.ename ,:old.jOb, :new.job, :old.mgr, :new.mgr,:old.sal,:new.sal, audit_package.reason); END IF; END;

AFTER INSERT OR UPDATE OR DELETE ON emp BEGIN CREATE TRIGGER cleanup_audit_emp AFTER INSERT OR UPDATE OR DELETE ON emp BEGIN audit_package. Reason:= NULL; END;

⑶ 数据完整性 ★ 利用系统服务保证数据的完整性 ● 保证标准的数据完整性的原则:不为 NUIL, 不能重复用主关键字和外部关键字。   ★ 利用系统服务保证数据的完整性 ● 保证标准的数据完整性的原则:不为 NUIL, 不能重复用主关键字和外部关键字。 ● 提供固定的缺省值。 ● 加强统计限制。 ● 动态设置 ENABLE和 DISABLE。

例子——利用系统服务保证数据的完整性管理。保证雇员的薪水不低于$500。   SQL> CREATE TABLE emp ( .... sal NUMBER(7,2) CHECK(sal>=500), );

★ 利用触发器增强数据的完整性   ● 加强非标准的数据完整性检查。 ● 提供可变的缺省值。 ● 提供动态约束。 ● 动态地 ENABLE和 DISABLE。

例子—一用触发器实现数据的完整性。确保薪水不能降低,但同时增长幅度一次不能超过10%。 CREATE TRIGGER check_sal BEFORE UPDATE OF saI ON emp FOR EACH ROW WHEN(new.sal<old.sal) OR (new.sal> old.sal*1.1) BEGIN RAISE_APPIICATION_ERROR(-20508, ‘Do not decrease salary nor increase by more than 10%’); END;

⑷ 参考完整性(关联完整性)

SQL> CREATE TABLE emp ( ... 例子----增强参考完整性。当删除父表DEPT中的某个部门时,同时删除子表EMP中该部门的职员。 SQL> CREATE TABLE emp ( ... deptno NUMBER(2) REFERENCES DEPT(DEPTNO) ON DELETE CASCADE);

★ 利用触发器增强参考完整性

例子----用触发器增强参考完整性约束。当DEPT表的DEPTNO发生变化时,EMP表相关行也要跟着进行适当的修改。 CREATE TRIGGER CASCADE_UPDATE AFTER UPDATE OF DEPTNO ON DEPT FOR EACH ROW BEGIN UPDATE EMP SET EMP.DEPTNO=:NEW.DEPTNO WHERE EMP.DEPTNO=:OLD.DEPTNO; END; 注意:本例只有在定义表DEPT和EMP时没有做参考完整性限制时才能正确执行。

⑸ 数据复制 ★ 利用系统的快照功能为表做复制 ● 按用户定义的时间间隔,定期异步地对表进行备份。 ● 把快照建立在多个主表上。   ★ 利用系统的快照功能为表做复制 ● 按用户定义的时间间隔,定期异步地对表进行备份。 ● 把快照建立在多个主表上。 ● 只能从快照中读数据,不能进行写操作。 ● 改善在主表上的数据操作性能,当发生网络失败时, 这一点尤其明显。

例子——利用快照拷贝表中数据。在旧金山创建一个建立在纽约的远地表上的快照。   CREATE SNAPSHOT emp_copy AS SELECT * FROM emp@ny; 注释:   ● 当创建快照时,不要再创建 AFTER型行级触发器,因为快照就是通过内部的 AFTER型行级触发器实现的。

★ 利用触发器复制表   ● 实时,同步地拷贝表中数据。 ● 表的复制通常只针对一个主表。 ● 既可从表的复制中读取数据,也可以往其中写 入数据。 ● 降低主表上的数据操作性能,这种情况在发生 网络失败时尤其突出。

例子——为一个表做复制。在纽约,为远地的旧金山制作一个基于本地表 EMP的复制。   CREATE TRIGGER emp_replica BEFORE INSERT OR UPDATE ON emp FOR EACH ROW DECLARE

IF :new.flag IS NULL THEN INSERT INTO emp@sf BEGIN IF INSERTING THEN IF :new.flag IS NULL THEN INSERT INTO emp@sf VALUES(:newempno,:new.ename,... ‘B’) ; :new.flag= ‘A’; END IF; EISE IF :new.flag= :old.flag THEN UPDATE emp@sf SET ename=:new.ename ,... flag= :new.flag WHERE empno= :new.empno; IF :old.flag=‘A’ THEN :new.flag=‘B’; :new.flag=‘A’; END;

6. 触发器的优点 除了具有存储过程的优点外,数据库触发器还有许多其它的优点: ★ 提高数据的安全性   除了具有存储过程的优点外,数据库触发器还有许多其它的优点: ★ 提高数据的安全性 ● 为数据操作提供了基于值的安全性检验机制 ● 为数据操作提供了基于值的审计 ★ 提高数据的完整性   ● 在数据库一级增强了数据完整性的动态限制。 ● 增强了复杂的参考完整性约束。 ● 确保一些相关的操作隐式地一起进行。