当前位置:Gxlcms > 数据库问题 > ORACLE PL/SQL编程总结(二)

ORACLE PL/SQL编程总结(二)

时间:2021-07-01 10:21:17 帮助过:9人阅读

 

      程序包(PACKAGE,简称包)是一组相关过程、函数、变量、常量和游标等PL/SQL程序设计元素的组合,作为一个完整的单元存储在数据库中,用名称来标识包。它具有面向对象程序设计语言的特点,是对这些PL/SQL 程序设计元素的封装。包类似于c#和JAVA语言中的类,其中变量相当于类中的成员变量,过程和函数相当于类方法。把相关的模块归类成为包,可使开发人员利用面向对象的方法进行存储过程的开发,从而提高系统性能。

       与高级语言中的类相同,包中的程序元素也分为公用元素和私用元素两种,这两种元素的区别是他们允许访问的程序范围不同,即它们的作用域不同。公用元素不仅可以被包中的函数、过程所调用,也可以被包外的PL/SQL程序访问,而私有元素只能被包内的函数和过程序所访问。

当然,对于不包含在程序包中的过程、函数是独立存在的。一般是先编写独立的过程与函数,待其较为完善或经过充分验证无误后,再按逻辑相关性组织为程序包

程序包的优点

u       简化应用程序设计:程序包的说明部分和包体部分可以分别创建各编译。主要体现     在以下三个方面:

1)        可以在设计一个应用程序时,只创建各编译程序包的说明部分,然后再编写引用该                     程序包的PL/SQL块。

2)        当完成整个应用程序的整体框架后,再回头来定义包体部分。只要不改变包的说明部分,就可以单独调试、增加或替换包体的内容,这不会影响其他的应用程序。

3)        更新包的说明后必须重新编译引用包的应用程序,但更新包体,则不需重新编译引用包的应用程序,以快速进行进行应用程序的原形开发。

u       模块化:可将逻辑相关的PL/SQL块或元素等组织在一起,用名称来唯一标识程序包。把一个大的功能模块划分人适当个数小的功能模块,分别完成各自的功能。这样组织的程序包都易于编写,易于理解更易于管理。

u       信息隐藏:因为包中的元素可以分为公有元素和私有元素。公有元素可被程序包内的过程、函数等的访问,还可以被包外的PL/SQL访问。但对于私有元素只能被包内的过程、函数等访问。对于用户,只需知道包的说明,不用了解包休的具体细节。

u       效率高:程序包在应用程序第一次调用程序包中的某个元素时,ORACLE将把整个程序包加载到内存中,当第二次访问程序包中的元素时,ORACLE将直接从内在中读取,而不需要进行磁盘I/O操作而影响速度,同时位于内在中的程序包可被同一会话期间的其它应用程序共享。因此,程序包增加了重用性并改善了多用户、多应用程序环境的效率。

对程序包的优点可总结如下:在PL/SQL程序设计中,使用包不仅可以使程序设计模块化,对外隐藏包内所使用的信息(通过使用私用变量),而写可以提高程序的执行效率。因为,当程序首次调用包内函数或过程时,ORACLE将整个包调入内存,当再次访问包内元素时,ORACLE直接从内存中读取,而不需要进行磁盘I/O操作,从而使程序执行效率得到提高。

    一个包由两个分开的部分组成:

    包说明(PACKAGE):包说明部分声明包内数据类型、变量、常量、游标、子程序和异常错误处理等元素,这些元素为包的公有元素。

    包主体(PACKAGE BODY):包主体则是包定义部分的具体实现,它定义了包定义部分所声明的游标和子程序,在包主体中还可以声明包的私有元素。

    包说明和包主体分开编译,并作为两部分分开的对象存放在数据库字典中,可查看数据字典user_source, all_source, dba_source,分别了解包说明与包主体的详细信息。

 

 

7.2  程序包的定义

 

程序包的定义分为程序包说明定义和程序包主体定义两部分组成。

程序包说明用于声明包的公用组件,如变量、常量、自定义数据类型、异常、过程、函数、游标等。包说明中定义的公有组件不仅可以在包内使用,还可以由包外其他过程、函数。但需要说明与注意的是,我们为了实现信息的隐藏,建议不要将所有组件都放在包说明处声明,只应把公共组件放在包声明部分。包的名称是唯一的,但对于两个包中的公有组件的名称可以相同,这种用“包名.公有组件名“加以区分。

包体是包的具体实现细节,其实现在包说明中声明的所有公有过程、函数、游标等。当然也可以在包体中声明仅属于自己的私有过程、函数、游标等。创建包体时,有以下几点需要注意:

u       包体只能在包说明被创建或编译后才能进行创建或编译。

u       在包体中实现的过程、函数、游标的名称必须与包说明中的过程、函数、游标一致,包括名称、参数的名称以及参数的模式(IN、OUT、IN OUT)。并建设按包说明中的次序定义包体中具体的实现。

u       在包体中声明的数据类型、变量、常量都是私有的,只能在包体中使用而不能被印刷体外的应用程序访问与使用。

u       在包体执行部分,可对包说明,包体中声明的公有或私有变量进行初始化或其它设置。

创建程序包说明语法格式:

CREATE [OR REPLACE] PACKAGE package_name
  [AUTHID {CURRENT_USER | DEFINER}]
  {IS | AS}
  [公有数据类型定义[公有数据类型定义]…]
  [公有游标声明[公有游标声明]…]
  [公有变量、常量声明[公有变量、常量声明]…]
  [公有函数声明[公有函数声明]…]
  [公有过程声明[公有过程声明]…]
END [package_name];

 

其中:AUTHIDCURRENT_USER和AUTHIDDEFINER选项说明应用程序在调用函数时所使用的权限模式,它们与CREATEFUNCTION语句中invoker_right_clause子句的作用相同。

 

创建程序包主体语法格式:

CREATE [OR REPLACE] PACKAGE BODY package_name
  {IS | AS}
  [私有数据类型定义[私有数据类型定义]…]
  [私有变量、常量声明[私有变量、常量声明]…]
  [私有异常错误声明[私有异常错误声明]…]
  [私有函数声明和定义[私有函数声明和定义]…]
  [私有函过程声明和定义[私有函过程声明和定义]…]
  [公有游标定义[公有游标定义]…]
  [公有函数定义[公有函数定义]…]
  [公有过程定义[公有过程定义]…]
BEGIN
  执行部分(初始化部分)
END package_name;

其中:在包主体定义公有程序时,它们必须与包定义中所声明子程序的格式完全一致。

 

 

7.3  包的开发步骤

 

与开发存储过程类似,包的开发需要几个步骤:

1.   将每个存储过程调式正确;

2.   用文本编辑软件将各个存储过程和函数集成在一起;

3.   按照包的定义要求将集成的文本的前面加上包定义;

4.   按照包的定义要求将集成的文本的前面加上包主体;

5.   使用SQLPLUS或开发工具进行调式。

 

 

7.4  包定义的说明

 对包内共有元素的调用格式为:包名.元素名称

 

 

7.5  子程序重载

       PL/SQL 允许对包内子程序和本地子程序进行重载。所谓重载时指两个或多个子程序有相同的名称,但拥有不同的参数变量、参数顺序或参数数据类型。

 

 

7.6  加密实用程序

 

ORACLE 提供了一个实用工具来加密或者包装用户的PL/SQL,它会将用户的PL/SQL改变为只有ORACLE能够解释的代码版本.

WRAP 实用工具位于$ORACLE_HOME/BIN。 

格式为:

WRAP INAME=<input_file_name> [ONAME=<output_file_name>]

wrap iname=e:\sample.txt

注意:在加密前,请将PL/SQL程序先保存一份,以备后用。

 

 

7.7  删除包

可以使用 DROP PACKAGE 命令对不需要的包进行删除,语法如下:

DROP PACKAGE [BODY] [user.]package_name;

DROP PROCEDURE OpenCurType; --删除存储过程
--删除我们实例中创建的各个包
DROP PACKAGE demo_pack;
DROP PACKAGE demo_pack1;
DROP PACKAGE emp_mgmt;
DROP PACKAGE emp_package;

 

 

7.8  包的管理

 

包与过程、函数一样,也是存储在数据库中的,可以随时查看其源码。若有需要,在创建包时可以随时查看更详细的编译错误。不需要的包也可以删除。

同样,为了避免调用的失败,在更新表的结构后,一定要记得重新编译依赖于它的程序包。在更新了包说明或包体后,也应该重新编译包说明与包体。语法如下:

ALTER PACKAGE package_name COMPILE [PACKAGE|BODY|SPECIFICATION];

也可以通过以下数据字典视图查看包的相关。

DBA_SOURCE, USER_SOURCE, USER_ERRORS,DBA-OBJECTS 

 

******************************************************************

----------把触发器说透----------

    触发器是许多关系数据库系统都提供的一项技术。在ORACLE系统里,触发器类似过程和函数,都有声明,执行和异常处理过程的PL/SQL块。

 

8.1 触发器类型

    触发器在数据库里以独立的对象存储,它与存储过程和函数不同的是,存储过程与函数需要用户显示调用才执行,而触发器是由一个事件来启动运行。即触发器是当某个事件发生时自动地隐式运行。并且,触发器不能接收参数。所以运行触发器就叫触发或点火(firing)。ORACLE事件指的是对数据库的表进行的INSERT、UPDATE及DELETE操作或对视图进行类似的操作。ORACLE将触发器的功能扩展到了触发ORACLE,如数据库的启动与关闭等。所以触发器常用来完成由数据库的完整性约束难以完成的复杂业务规则的约束,或用来监视对数据库的各种操作,实现审计的功能。

8.1.1  DML触发器

ORACLE可以在DML语句进行触发,可以在DML操作前或操作后进行触发,并且可以对每个行或语句操作上进行触发。

8.1.2  替代触发器

    由于在ORACLE里,不能直接对由两个以上的表建立的视图进行操作。所以给出了替代触发器。它就是ORACLE 8专门为进行视图操作的一种处理方法。

8.1.3  系统触发器

 

ORACLE 8i 提供了第三种类型的触发器叫系统触发器。它可以在ORACLE数据库系统的事件中进行触发,如ORACLE系统的启动与关闭等。 

  触发器组成: 

  l   触发事件:引起触发器被触发的事件。 例如:DML语句(INSERT, UPDATE, DELETE语句对表或视图执行数据处理操作)、DDL语句(如CREATE、ALTER、DROP语句在数据库中创建、修改、删除模式对象)、数据库系统事件(如系统启动或退出、异常错误)、用户事件(如登录或退出数据库)。

  l   触发时间:即该TRIGGER 是在触发事件发生之前(BEFORE)还是之后(AFTER)触发,也就是触发事件和该TRIGGER 的操作顺序。

  l   触发操作:即该TRIGGER 被触发之后的目的和意图,正是触发器本身要做的事情。 例如:PL/SQL 块。

  l   触发对象:包括表、视图、模式、数据库。只有在这些对象上发生了符合触发条件的触发事件,才会执行触发操作。

  l   触发条件:由WHEN子句指定一个逻辑表达式。只有当该表达式的值为TRUE时,遇到触发事件才会自动执行触发器,使其执行触发操作。

  l   触发频率:说明触发器内定义的动作被执行的次数。即语句级(STATEMENT)触发器和行级(ROW)触发器。

语句级(STATEMENT)触发器:是指当某触发事件发生时,该触发器只执行一次;

行级(ROW)触发器:是指当某触发事件发生时,对受到该操作影响的每一行数据,触发器都单独执行一次。


编写触发器时,需要注意以下几点:

 

    ?    ?    ?l  触发器不接受参数。

    ?    ?    ?l   一个表上最多可有12个触发器,但同一时间、同一事件、同一类型的触发器只能有一个。并各触发器之间不能有矛盾。

    ?    ?    ?l  在一个表上的触发器越多,对在该表上的DML操作的性能影响就越大。

    ?    ?    ?l  触发器最大为32KB。若确实需要,可以先建立过程,然后在触发器中用CALL语句进行调用。

    ?    ?    ?l  在触发器的执行部分只能用DML语句(SELECT、INSERT、UPDATE、DELETE),不能使用DDL语句(CREATE、ALTER、DROP)

    ?    ?    ?l 触发器中不能包含事务控制语句(COMMIT,ROLLBACK,SAVEPOINT)。因为触发器是触发语句的一部分,触发语句被提交、回退时,触发器也被提交、回退了。

    ?    ?    ?l  在触发器主体中调用的任何过程、函数,都不能使用事务控制语句。

    ?    ?    ?l  在触发器主体中不能申明任何Long和blob变量。新值new和旧值old也不能向表中的任何long和blob列。

    ?    ?    ?l  不同类型的触发器(如DML触发器、INSTEAD OF触发器、系统触发器)的语法格式和作用有较大区别。 

 

8.2 创建触发器

 

创建触发器的一般语法是: 

1 2 3 4 5 6 7 8 9 CREATE [OR REPLACETRIGGER trigger_name {BEFORE | AFTER } {INSERT DELETE UPDATE [OF column [, column …]]} [OR {INSERT DELETE UPDATE [OF column [, column …]]}...] ON [schema.]table_name | [schema.]view_name [REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}] [FOR EACH ROW ] [WHEN condition] PL/SQL_BLOCK | CALL procedure_name;

其中:

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

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

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

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

    当一个基表被修改( INSERT, UPDATE, DELETE)时要执行的存储过程,执行时根据其所依附的基表改动而自动触发,因此与应用程序无关,用数据库触发器可以保证数据的一致性和完整性。

 

每张表最多可建立12 种类型的触发器,它们是:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 BEFORE INSERT BEFORE INSERT FOR EACH ROW AFTER INSERT AFTER INSERT FOR EACH ROW      BEFORE UPDATE BEFORE UPDATE FOR EACH ROW AFTER UPDATE AFTER UPDATE FOR EACH ROW      BEFORE DELETE BEFORE DELETE FOR EACH ROW AFTER DELETE AFTER DELETE FOR EACH ROW 

 

8.2.1  触发器触发次序

1.        执行 BEFORE语句级触发器;

2.        对与受语句影响的每一行:

l         执行 BEFORE行级触发器

l         执行 DML语句

l         执行 AFTER行级触发器 

3.        执行 AFTER语句级触发器

 

8.2.2  创建DML触发器

 

    ?    ?   ?触发器名与过程名和包的名字不一样,它是单独的名字空间,因而触发器名可以和表或过程有相同的名字,但在一个模式中触发器名不能相同。 

    ?    ?    ?DML触发器的限制

    ?    ?    ?l         CREATE TRIGGER语句文本的字符长度不能超过32KB;

    ?    ?    ?l         触发器体内的SELECT 语句只能为SELECT … INTO …结构,或者为定义游标所使用的SELECT 语句。

    ?    ?    ?l         触发器中不能使用数据库事务控制语句 COMMIT; ROLLBACK, SVAEPOINT 语句;

    ?    ?    ?l         由触发器所调用的过程或函数也不能使用数据库事务控制语句;

    ?    ?    ?l         触发器中不能使用LONG, LONG RAW 类型;

    ?    ?    ?l         触发器内可以参照LOB 类型列的列值,但不能通过 :NEW 修改LOB列中的数据; 

    ?    ?    ?DML触发器基本要点

    ?    ?    ?l         触发时机:指定触发器的触发时间。如果指定为BEFORE,则表示在执行DML操作之前触发,以便防止某些错误操作发生或实现某些业务规则;如果指定为AFTER,则表示在执行DML操作之后触发,以便记录该操作或做某些事后处理。

    ?    ?    ?l         触发事件:引起触发器被触发的事件,即DML操作(INSERT、UPDATE、DELETE)。既可以是单个触发事件,也可以是多个触发事件的组合(只能使用OR逻辑组合,不能使用AND逻辑组合)。

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

    ?    ?    ?1)。INSERTING当触发事件是INSERT时,取值为TRUE,否则为FALSE。

    ?    ?    ?2)。UPDATING [column_1,column_2,…,column_x]当触发事件是UPDATE      时,如果修改了column_x列,则取值为TRUE,否则为FALSE。其中column_x是可选的。

    ?    ?    ?3)。DELETING当触发事件是DELETE时,则取值为TRUE,否则为FALSE。

    ?    ?    ?解发对象:指定触发器是创建在哪个表、视图上。

    ?    ?    ?l         触发类型:是语句级还是行级触发器。

    ?    ?    ?l         触发条件:由WHEN子句指定一个逻辑表达式,只允许在行级触发器上指定触发条件,指定UPDATING后面的列的列表。 

    ?    ?    ?  问题:当触发器被触发时,要使用被插入、更新或删除的记录中的列值,有时要使用操作前、        后列的值.

    ?    ?    ?  实现:  :NEW 修饰符访问操作完成后列的值

 

 :OLD 修饰符访问操作完成前列的值 

特性

INSERT

UPDATE

DELETE

OLD

NULL

实际值

实际值

NEW

实际值

实际值

NULL

例1: 建立一个触发器, 当职工表 emp 表被删除一条记录时,把被删除记录写到职工表删除日志表中去。

 

1 2 3 4 5 6 7 8 9 10 11 12 13 CREATE TABLE emp_his AS SELECT FROM EMP WHERE 1=2; CREATE OR REPLACE TRIGGER tr_del_emp    BEFORE DELETE --指定触发时机为删除操作前触发    ON scott.emp    FOR EACH ROW   --说明创建的是行级触发器 BEGIN    --将修改前数据插入到日志记录表 del_emp ,以供监督使用。    INSERT INTO emp_his(deptno , empno, ename , job ,mgr , sal , comm , hiredate )        VALUES( :old.deptno, :old.empno, :old.ename , :old.job,:old.mgr, :old.sal, :old.comm, :old.hiredate ); END; DELETE emp WHERE empno=7788; DROP TABLE emp_his; DROP TRIGGER del_emp;

例2:在触发器中调用过程。

 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 CREATE OR REPLACE PROCEDURE add_job_history  ( p_emp_id          job_history.employee_id%type    , p_start_date      job_history.start_date%type   , p_end_date        job_history.end_date%type    , p_job_id          job_history.job_id%type    , p_department_id   job_history.department_id%type    ) IS BEGIN  INSERT INTO job_history (employee_id, start_date, end_date,                            job_id, department_id)   VALUES(p_emp_id, p_start_date, p_end_date, p_job_id, p_department_id); END add_job_history;   --创建触发器调用存储过程... CREATE OR REPLACE TRIGGER update_job_history  AFTER UPDATE OF job_id, department_id ON employees  FOR EACH ROW BEGIN  add_job_history(:old.employee_id, :old.hire_date, sysdate,                   :old.job_id, :old.department_id); END;

 

8.2.3  创建替代(INSTEAD OF)触发器

 

创建触发器的一般语法是: 

1 2 3 4 5 6 7 8 9 CREATE [OR REPLACETRIGGER trigger_name INSTEAD OF {INSERT DELETE UPDATE [OF column [, column …]]} [OR {INSERT DELETE UPDATE [OF column [, column …]]}...] ON [schema.] view_name --只能定义在视图上 [REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}] [FOR EACH ROW ] --因为INSTEAD OF触发器只能在行级上触发,所以没有必要指定 [WHEN condition] PL/SQL_block | CALL procedure_name;

其中:

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

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

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

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

    INSTEAD_OF 用于对视图的DML触发,由于视图有可能是由多个表进行联结(join)而成,因而并非是所有的联结都是可更新的。但可以按照所需的方式执行更新,例如下面情况:

 

1 

1 2 3 CREATE OR REPLACE VIEW emp_view AS SELECT deptno, count(*) total_employeer, sum(sal) total_salary FROM emp GROUP BY deptno;

  在此视图中直接删除是非法: 

1 2 SQL>DELETE FROM emp_view WHERE deptno=10; DELETE FROM emp_view WHERE deptno=10

   ERROR 位于第 1 行:

  ORA-01732: 此视图的数据操纵操作非法 

  但是我们可以创建INSTEAD_OF触发器来为 DELETE 操作执行所需的处理,即删除EMP表中所有基准行:  

1 2 3 4 5 6 7 8 9 10 11 CREATE OR REPLACE TRIGGER emp_view_delete    INSTEAD OF DELETE ON emp_view FOR EACH ROW BEGIN    DELETE FROM emp WHERE deptno= :old.deptno; END emp_view_delete;   DELETE FROM emp_view WHERE deptno=10;   DROP TRIGGER emp_view_delete;   DROP VIEW emp_view;

  例2创建复杂视图,针对INSERT操作创建INSTEAD OF触发器,向复杂视图插入数据。

  l         创建视图:

 

1 2 3 4 5 6 7 8 9 CREATE OR REPLACE FORCE VIEW "HR"."V_REG_COU" ("R_ID""R_NAME""C_ID""C_NAME") AS  SELECT r.region_id,     r.region_name,     c.country_id,     c.country_name  FROM regions r,     countries c  WHERE r.region_id = c.region_id;

  l         创建触发器: 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 CREATE OR REPLACE TRIGGER "HR"."TR_I_O_REG_COU" INSTEAD OF  INSERT ON v_reg_cou FOR EACH ROW DECLARE v_count NUMBER; BEGIN  SELECT COUNT(*) INTO v_count FROM regions WHERE region_id = :new.r_id;  IF v_count = 0 THEN     INSERT INTO regions       (region_id, region_name       VALUES       (:new.r_id, :new.r_name       );  END IF;    SELECT COUNT(*) INTO v_count FROM countries WHERE country_id = :new.c_id;  IF v_count = 0 THEN     INSERT     INTO countries       (         country_id,         country_name,         region_id       )       VALUES       (         :new.c_id,         :new.c_name,         :new.r_id       );  END IF; END;

?

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

    ?    ?l         只能被创建在视图上,并且该视图没有指定WITH CHECK OPTION选项。

    ?    ?l         不能指定BEFORE 或 AFTER选项。

    ?    ?l         FOR EACH ROW子可是可选的,即INSTEAD OF触发器只能在行级上触发、或只能是行级触发器,没有必要指定。

    ?    ?l         没有必要在针对一个表的视图上创建INSTEAD OF触发器,只要创建DML触发器就可以了。


8.2.4  创建系统事件触发器

 

ORACLE10G提供的系统事件触发器可以在DDL或数据库系统上被触发。DDL指的是数据定义语言,如CREATE 、ALTER及DROP 等。而数据库系统事件包括数据库服务器的启动或关闭,用户的登录与退出、数据库服务错误等。创建系统触发器的语法如下: 

  创建触发器的一般语法是: 

1 2 3 4 5 6 CREATE OR REPLACE TRIGGER [sachema.]trigger_name {BEFORE|AFTER} {ddl_event_list | database_event_list} ON DATABASE | [schema.]SCHEMA } [WHEN condition] PL/SQL_block | CALL procedure_name;

  其中: ddl_event_list:一个或多个DDL 事件,事件间用 OR 分开;

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

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

  下面给出系统触发器的种类和事件出现的时机(前或后):

事件

允许的时机

说明

STARTUP

AFTER

启动数据库实例之后触发

SHUTDOWN

BEFORE

关闭数据库实例之前触发(非正常关闭不触发)

SERVERERROR

AFTER

数据库服务器发生错误之后触发

LOGON

AFTER

成功登录连接到数据库后触发

LOGOFF

BEFORE

开始断开数据库连接之前触发

CREATE

BEFORE,AFTER

在执行CREATE语句创建数据库对象之前、之后触发

DROP

BEFORE,AFTER

在执行DROP语句删除数据库对象之前、之后触发

ALTER

BEFORE,AFTER

在执行ALTER语句更新数据库对象之前、之后触发

DDL

BEFORE,AFTER

在执行大多数DDL语句之前、之后触发

GRANT

BEFORE,AFTER

执行GRANT语句授予权限之前、之后触发

REVOKE

BEFORE,AFTER

执行REVOKE语句收权限之前、之后触犯发

RENAME

BEFORE,AFTER

执行RENAME语句更改数据库对象名称之前、之后触犯发

AUDIT NOAUDIT

BEFORE,AFTER

执行AUDITNOAUDIT进行审计或停止审计之前、之后触发

 

8.2.5  系统触发器事件属性

 

事件属性\事件

Startup/Shutdown

Servererror

Logon/Logoff

DDL

DML

事件名称

?

?

?

?

数据库名称

?

       

数据库实例号

?

       

错误号

 

?

     

用户名

   

?

 

模式对象类型

     

?

模式对象名称

     

?

       

?

   除DML语句的列属性外,其余事件属性值可通过调用ORACLE定义的事件属性函数来读取。

函数名称

数据类型

说    明

Ora_sysevent

VARCHAR2(20)

激活触发器的事件名称

Instance_num

NUMBER

数据库实例名

Ora_database_name

VARCHAR2(50)

数据库名称

Server_error(posi)

NUMBER

错误信息栈中posi指定位置中的错误号

 

 

Is_servererror(err_number)

 

 

BOOLEAN

检查err_number指定的错误号是否在错误信息栈中,如果在则返回TRUE,否则返回FALSE。在触发器内调用此函数可以判断是否发生指定的错误。

Login_user

VARCHAR2(30)

登陆或注销的用户名称

Dictionary_obj_type

VARCHAR2(20)

DDL语句所操作的数据库对象类型

Dictionary_obj_name

VARCHAR2(30)

DDL语句所操作的数据库对象名称

Dictionary_obj_owner

VARCHAR2(30)

DDL语句所操作的数据库对象所有者名称

Des_encrypted_password

VARCHAR2(2)

正在创建或修改的经过DES算法加密的用户口令

 

1创建触发器,存放有关事件信息。 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 DESC ora_sysevent DESC ora_login_user   --创建用于记录事件用的表   CREATE TABLE ddl_event (crt_date timestamp PRIMARY KEY,

人气教程排行