Oracle数据库之PL/SQL触发器

1. 介绍

触发器(trigger)是数据库提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作(insert,delete,update)时就会激活它执行。触发器经常用于加强数据的完整性约束和业务规则等。

ORACLE触发器有三种类型,分别是:DML触发器、替代触发器和系统触发器。

DML触发器

顾名思义,DML触发器是由DML语句触发的。例如数据库的INSERT、UPDATE、DELETE操作都可以触发该类型的触发器。它们可以在这些语句之前或之后触发,或者在行级上触发(就是说对于每个受影响的行都触发一次)。

替代触发器

替代触发器只能使用在视图上,与DML不同的是,DML触发器是运行在DML之外的,而替代触发器是代替激发它的DML语句运行。替代触发器是行触发器。

系统触发器

这种触发器是发生在如数据库启动或关闭等系统事件时,不是在执行DML语句时发生,当然也可以在DDL时触发。

触发器功能强大,轻松可靠地实现许多复杂的功能,但是我们也应该慎用。为什么又要慎用呢?触发器本身没有过错,但如果我们滥用,会造成数据库及应用程序的维护困难。在数据库操作中,我们可以通过关系、触发器、存储过程、应用程序等来实现数据操作,同时约束、缺省值也是保证数据完整性的重要保障。如果我们对触发器过分的依赖,势必影响数据库的结构,同时增加了维护的复杂程度。

2. 触发器组成

触发器主要由以下几个要素组成:

  1. 触发事件:引起触发器被触发的事件。
  2. 触发时间:触发器是在触发事件发生之前(BEFORE)还是之后(AFTER)触发,也就是触发事件和该触发器的操作顺序。
  3. 触发操作:触发器被触发之后的目的和意图,是触发器本身要做的事情。
  4. 触发对象:包括表、视图、模式、数据库。只有在这些对象上发生了符合触发条件的触发事件,才会执行触发操作。
  5. 触发条件:由WHEN子句指定一个逻辑表达式。只有当该表达式的值为TRUE时,遇到触发事件才会自动执行触发器,使其执行触发操作。
  6. 触发频率:说明触发器内定义的动作被执行的频率。即语句级(STATEMENT)触发器和行级(ROW)触发器: 
    语句级(STATEMENT)触发器:是指当某触发事件发生时,该触发器只执行一次; 
    行级(ROW)触发器:是指当某触发事件发生时,对受到该操作影响的每一行数据,触发器都单独执行一次。

3. 创建触发器

语法:

 1 CREATE [ OR REPLACE ] TRIGGER plsql_trigger_source 

 1 plsql_trigger_source ::========
 2
 3 [schema.] trigger_name
 4   { simple_dml_trigger
 5   | instead_of_dml_trigger
 6   | compound_dml_trigger
 7   | system_trigger
 8   }
 9
10 simple_dml_trigger ::========
11
12 { BEFORE | AFTER } dml_event_clause [ referencing_clause ] [ FOR EACH ROW ]
13   [ trigger_edition_clause ] [ trigger_ordering_clause ]
14     [ ENABLE | DISABLE ] [ WHEN ( condition ) ] trigger_body
15
16 instead_of_dml_trigger ::=
17
18 INSTEAD OF { DELETE | INSERT | UPDATE } [ OR { DELETE | INSERT | UPDATE } ]...
19 ON [ NESTED TABLE nested_table_column OF ] [ schema. ] noneditioning_view
20 [ referencing_clause ] [ FOR EACH ROW ]
21 [ trigger_edition_clause ] [ trigger_ordering_clause ]
22 [ ENABLE | DISABLE ] trigger_body
23
24 system_trigger ::=======
25
26 { BEFORE | AFTER | INSTEAD OF }
27 { ddl_event [OR ddl_event]...
28 | database_event [OR database_event]...
29 }
30 ON { [schema.] SCHEMA
31    | DATABASE
32    }
33 [ trigger_ordering clause ]
34
35 dml_event_clause ::============
36
37 { DELETE | INSERT | UPDATE [ OF column [, column ]... ] }
38 [ OR { DELETE | INSERT | UPDATE [ OF column [, column]... ] }...
39 ON [ schema.] { table | view }
40
41 referencing_clause ::==========
42
43 REFERENCING
44  { OLD [ AS ] old
45  | NEW [ AS ] new
46  | PARENT [ AS ] parent
47  }...
48
49 trigger_body ::=======
50
51 { plsql_block | CALL routine_clause }

说明:

BEFORE和AFTER指出触发器的触发时间分别为前触发和后触发方式,前触发是在执行触发事件之前触发当前所创建的触发器,后触发是在执行触发事件之后触发当前所创建的触发器。

REFERENCING子句说明相关名称,在行触发器的PL/SQL块和WHEN子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句中则不能加冒号。

NEW只在UPDATE、INSERT的DML触发器内可用,它包含了修改发生后被影响行的值。

OLD只在UPDATE、DELETE的DML触发器内可用,它包含了修改发生前被影响行的值。

FOR EACH ROW选项说明触发器为行触发器。行触发器和语句触发器的区别表现在:行触发器要求当一个DML语句操走影响数据库中的多行数据时,对于其中的每个数据行,只要它们符合触发约束条件,均激活一次触发器;而语句触发器将整个语句操作作为触发事件,当它符合约束条件时,激活一次触发器。当省略FOR EACH ROW 选项时,BEFORE和AFTER触发器为语句触发器,而INSTEAD OF触发器则只能为行触发器。

WHEN子句说明触发约束条件。Condition为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL函数。WHEN子句指定的触发约束条件只能用在BEFORE和AFTER行触发器中,不能用在INSTEAD OF行触发器和其它类型的触发器中。

INSTEAD OF选项(创建替代触发器)使ORACLE激活触发器,而不执行触发事件。只能对视图和对象视图建立INSTEAD OF触发器,而不能对表、模式和数据库建立INSTEAD OF触发器。

ddl_event:一个或多个DDL事件,事件间用OR分开。

database_event:一个或多个数据库事件,事件间用OR分开。

示例1,在插入数据时,自动使用序列编号:

1 CREATE OR REPLACE TRIGGER EMP_INSERT_ID
2 BEFORE INSERT ON employee FOR EACH ROW
3 BEGIN
4    SELECT SEQ_ID.NEXTVAL INTO :NEW.ID FROM DUAL;
5 END;
 1 示例2,在多表联接的视图中插入数据:
 2
 3 -- 创建视图
 4 CREATE OR REPLACE VIEW vw_emp AS
 5 SELECT e.name ename, e.address, d.name dname
 6 FROM employee e, dept d
 7 WHERE e.did = d.id;
 8
 9 -- 创建触发器
10 CREATE TRIGGER emp_insert_trigger
11    INSTEAD OF INSERT ON vw_emp
12 DECLARE
13    v_did dept.id%TYPE;
14 BEGIN
15    SELECT id INTO v_did FROM dept WHERE name = :NEW.dname;
16    INSERT INTO emp (name, address, did) VALUES (:NEW.ename, :NEW.address, v_did);
17 END emp_insert_trigger;
 1 示例3,创建实例启动触发器:
 2
 3 -- 创建记录操作事件的表
 4 CREATE TABLE event_table(
 5    event VARCHAR2(50),
 6    time DATE
 7 );
 8
 9 -- 创建触发器
10 CREATE OR REPLACE TRIGGER tr_startup
11    AFTER STARTUP
12    ON DATABASE
13 BEGIN
14    INSERT INTO event_table(event, time)
15     VALUES(ora_sysevent, SYSDATE);
16 END;

 DML触发器

DML触发器对我们开发人员来说是最常用的。DML触发器是由数据库的INSERT、UPDATE、DELETE操作触发,该类触发器可以在上述语句之前或之后执行,也可以每个受影响的行执行一次。

条件谓词:当在触发器中包含多个触发事件(INSERT、UPDATE、DELETE)的组合时,为了分别针对不同的事件进行不同的处理,需要使用ORACLE提供的条件谓词:

  1. INSERTING:当触发事件是INSERT时,取值为TRUE,否则为FALSE。
  2. UPDATING [(column_1,column_2,…,column_x)]:当触发事件是UPDATE时,如果修改了column_x列,则取值为TRUE,否则为FALSE。
  3. DELETING:当触发事件是DELETE时,则取值为TRUE,否则为FALSE。

示例:

 1 CREATE OR REPLACE TRIGGER emp_sal_trigger
 2    BEFORE UPDATE OF salary OR DELETE
 3    ON employee FOR EACH ROW
 4    WHEN (old.did = 1)
 5 BEGIN
 6   CASE
 7      WHEN UPDATING (‘salary‘) THEN
 8         IF :NEW.salary < :old.salary THEN
 9            RAISE_APPLICATION_ERROR(-20001, ‘部门1的员工工资不能降‘);
10         END IF;
11      WHEN DELETING THEN
12           RAISE_APPLICATION_ERROR(-20002, ‘不能删除部门1的员工记录‘);
13   END CASE;
14 END emp_sal_trigger;

5. 替代触发器

INSTEAD OF用于对视图的DML触发,由于视图有可能是由多个表联结(JOIN)而成,因而并非所有的视图都是可更新的,但可以按照所需的方式执行更新。

创建INSTEAD OF触发器需要注意以下几点:

  1. 只能被创建在视图上,并且该视图没有指定WITH CHECK OPTION选项。
  2. 不能指定BEFORE或AFTER选项。
  3. FOR EACH ROW子句是可选的。
  4. 没有必要在针对一个表的视图上创建INSTEAD OF触发器,只要创建DML触发器就可以了。

示例:

1 CREATE OR REPLACE TRIGGER emp_delete_trigger
2    INSTEAD OF DELETE ON vw_emp FOR EACH ROW
3 DECLARE
4    v_did dept.id%TYPE;
5 BEGIN
6    SELEC id INTO v_did FROM dept WHERE name=:OLD.dname;
7    DELETE FROM employee WHERE did= v_did;
8 END emp_delete_trigger;

6. 系统触发器

系统触发器可以在DDL或数据库系统上被触发,数据库系统事件包括数据库服务器的启动或关闭,用户的登录与退出、数据库服务错误等。

系统事件触发器既可以建立在一个模式上,又可以建立在整个数据库上。当建立在模式(SCHEMA)之上时,只有模式所指定用户的DDL操作和它们所导致的错误才激活触发器,默认时为当前用户模式。当建立在数据库(DATABASE)之上时,该数据库所有用户的DDL操作和他们所导致的错误,以及数据库的启动和关闭均可激活触发器。

系统触发器的种类和事件出现的时机:

 1 -- 创建记录用户登录注销日志的表
 2 CREATE TABLE log_on_off_log
 3 (user_name VARCHAR2(20),
 4  logon_date timestamp,
 5  logoff_date timestamp);
 6
 7 -- 创建登录触发器
 8 CREATE OR REPLACE TRIGGER logon_trigger
 9    AFTER LOGON ON DATABASE
10 BEGIN
11    INSERT INTO log_on_off_log (user_name, logon_date) VALUES (ora_login_user, systimestamp);
12 END logon_trigger;
13
14 -- 创建退出触发器
15 CREATE OR REPLACE TRIGGER logoff_trigger
16    BEFORE LOGOFF ON DATABASE
17 BEGIN
18    INSERT INTO log_on_off_log (user_name, logoff_date) VALUES (ora_login_user, systimestamp);
19 END logoff_trigger;
事件 触发时机 说明
STARTUP AFTER 启动数据库实例之后触发
SHUTDOWN BEFORE 关闭数据库实例之前触发
SERVERERROR AFTER 数据库服务器发生错误之后触发
LOGON AFTER 成功登录到数据库后触发
LOGOFF BEFORE 断开数据库连接之前触发
DDL BEFORE,AFTER 在执行大多数DDL语句之前、之后触发
CREATE / ALTER / DROP BEFORE,AFTER 在执行CREATE或ALTER或DROP语句创建数据库对象之前、之后触发
RENAME BEFORE,AFTER 执行RENAME语句更改数据库对象名称之前、之后触发
GRANT / REVOKE BEFORE,AFTER 执行GRANT语句授予权限或REVOKE撤销权限之前、之后触发
AUDIT / NOAUDIT BEFORE,AFTER 执行AUDIT或NOAUDIT进行审计或停止审计之前、之后触发

时间: 2024-10-09 23:36:53

Oracle数据库之PL/SQL触发器的相关文章

ORACLE数据库之PL/SQL触发器、rownum、动态SQL、数据库之视图与索引

WHEN子句说明触发约束条件.Condition为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL函数.WHEN子句指定的触发约束条件只能用在BEFORE和AFTER行触发器中,不能用在INSTEAD OF行触发器和其它类型的触发器中. -- 创建记录操作事件的表 CREATE TABLE event_table( event VARCHAR2(50), time DATE ); -- 创建触发器 CREATE OR REPLACE TRIGGER tr_star

Oracle数据库之PL/SQL过程与函数

Oracle数据库之PL/SQL过程与函数 PL/SQL块分为匿名块与命名块,命名块又包含子程序.包和触发器. 过程和函数统称为PL/SQL子程序,我们可以将商业逻辑.企业规则写成过程或函数保存到数据库中,以便共享. 过程和函数均存储在数据库中,并通过参数与其调用者交换信息.过程和函数的唯一区别是函数总向调用者返回数据,而过程不返回数据. 1. 存储过程概念 存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL语句集,存储在数据库中.经过第一次编译后再次

Oracle数据库之PL/SQL异常处理

Oracle数据库之PL/SQL异常处理 异常指的是在程序运行过程中发生的异常事件,通常是由硬件问题或者程序设计问题所导致的. PL/SQL程序设计过程中,即使是写得最好的程序也可能会遇到错误或未预料到的事件.一个健壮的程序都应该能够正确处理各种异常情况,并尽可能从中恢复. 1. 异常处理 异常处理是用来处理正常执行过程中未预料的事件.PL/SQL程序块一旦产生异常而没有指出如何处理时,程序就会自动终止整个程序运行. PL/SQL编程过程中,有三种类型的异常: 1.预定义异常 对这种异常情况的处

Oracle数据库之PL/SQL程序设计简介

有利于客户/服务器环境应用的运行 对于客户/服务器环境来说,真正的瓶颈是网络上.无论网络多快,只要客户端与服务器进行大量的数据交换,应用运行的效率自然就回受到影响.如果使用PL/SQL进行编程,将这种具有大量数据处理的应用放在服务器执行,自然就省去了数据在网上的传输时间. 适合于客户环境 PL/SQL由于分为数据库PL/SQL部分和工具PL/SQL.对于客户端来说,PL/SQL可以嵌套到相应的工具中,客户端程序可以执行本地包含PL/SQL部分,也可以向服务发SQL命令或激活服务器端的PL/SQL

Oracle数据库之PL/SQL程序基础设计

http://www.cnblogs.com/hellokitty1/p/4572930.html DECLARE /* * 声明部分——定义常量.变量.复杂数据类型.游标.用户自定义异常 */ BEGIN /* * 执行部分——PL/SQL语句和SQL语句 */ EXCEPTION /* * 异常处理部分——处理运行异常 */ END; /*块结束标记 */ 要实现PL/SQL程序设计,先介绍如下的基本内容: 二.标识符 PL/SQL程序设计中的标识符定义与SQL的标识符定义的要求相同: 标识

Oracle数据库之PL/SQL游标

1. 游标概念 字面意思是游动的光标,是指向上下文区域的句柄或指针. 在PL/SQL块中执行CRUD操作时,ORACLE会在内存中为其分配上下文区.用数据库语言来描述游标就是:映射在上下文区结果集中一行数据上的位置实体. 用户可以使用游标访问结果集中的任意一行数据,将游标指向某行后,即可对该行数据进行操作.游标为应用提供了一种对具有多行数据查询结果集中的每一行数据分别进行单独处理的方法,是设计嵌入式SQL语句的应用程序的常用编程方式. 在每个用户会话中,可以同时打开多个游标,其最大数量由数据库初

Oracle数据库之PL/SQL程序设计基础

PL/SQL程序设计基础 一.PL/SQL块结构 前边我们已经介绍了PL/SQL块的结构,再来回顾一下: DECLARE /* * 声明部分——定义常量.变量.复杂数据类型.游标.用户自定义异常 */ BEGIN /* * 执行部分——PL/SQL语句和SQL语句 */ EXCEPTION /* * 异常处理部分——处理运行异常 */ END; /*块结束标记 */ 要实现PL/SQL程序设计,先介绍如下的基本内容: 二.标识符 PL/SQL程序设计中的标识符定义与SQL的标识符定义的要求相同:

oracle数据库使用PL/sql导入excel数据

1.打开PL/SQL工具,菜单进入   工具>ODBC导入器(菜单列表倒数第二): 2.连接数据库与选择导入的excel文件表: 3.选择导入的表以及excel与数据库表字段之间的对应关系: 原文地址:https://www.cnblogs.com/whitemouseV2-0/p/10837714.html

每周一书《Oracle 12 c PL(SQL)程序设计终极指南》

本周为大家送出的书是<Oracle 12 c PL(SQL)程序设计终极指南>,此书由机械工业出版社出版, 孙风栋,王澜,郭晓惠 著. 内容简介: <Oracle 12c PL/SQL程序设计终极指南>志在打造PL/SQL领域最为系统.全面.实战.权威的著作,通过一系列非常突出的优势在大量的同类书中脱颖而出,成为该领域的标准读物. PL/SQL本身涉及的知识点浩瀚.庞杂,初学者根本无法依靠自身能力理清头绪,学习成本极高.本书对知识点进行了体系化的梳理,化繁杂为有序,突出重点,直指核