Oracle触发器
|
?????????? REFERENCING 子句说明相关名称,在行触发器的PL/SQL块和WHEN 子句中可以使用相关名称参照当前的新、旧列值,默认的相关名称分别为OLD和NEW。触发器的PL/SQL块中应用相关名称时,必须在它们之前加冒号(:),但在WHEN子句中则不能加冒号。 WHEN 子句说明触发约束条件。Condition 为一个逻辑表达时,其中必须包含相关名称,而不能包含查询语句,也不能调用PL/SQL 函数。WHEN 子句指定的触发约束条件只能用在BEFORE 和AFTER 行触发器中,不能用在INSTEAD OF 行触发器和其它类型的触发器中。 ??? INSTEAD_OF 用于对视图的DML触发,由于视图有可能是由多个表进行联结(join)而成,因而并非是所有的联结都是可更新的。但可以按照所需的方式执行更新,例如下面情况: 例1: CREATE OR REPLACE VIEW emp_view AS SELECT deptno,count(*) total_employeer,sum(sal) total_salary FROM emp GROUP BY deptno; 在此视图中直接删除是非法: SQL>DELETE FROM emp_view WHERE deptno=10; DELETE FROM emp_view WHERE deptno=10 ERROR 位于第 1 行: ORA-01732: 此视图的数据操纵操作非法 但是我们可以创建INSTEAD_OF触发器来为 DELETE 操作执行所需的处理,即删除EMP表中所有基准行: 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???????? 创建视图: 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??????? 创建触发器: 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.3 创建系统事件触发器 ??? ORACLE10G提供的系统事件触发器可以在DDL或数据库系统上被触发。DDL指的是数据定义语言,如CREATE 、ALTER及DROP 等。而数据库系统事件包括数据库服务器的启动或关闭,用户的登录与退出、数据库服务错误等。创建系统触发器的语法如下: 创建触发器的一般语法是: 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 执行AUDIT或NOAUDIT进行审计或停止审计之前、之后触发 8.2.4 系统触发器事件属性 事件属性事件 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:创建触发器,存放有关事件信息。 DESC ora_sysevent DESC ora_login_user --创建用于记录事件用的表 CREATE TABLE ddl_event (crt_date timestamp PRIMARY KEY, event_name VARCHAR2(20), user_name VARCHAR2(10), obj_type VARCHAR2(20), obj_name VARCHAR2(20)); --创建触犯发器 CREATE OR REPLACE TRIGGER tr_ddl AFTER DDL ON SCHEMA BEGIN ?? INSERT INTO ddl_event VALUES ?? (systimestamp,ora_sysevent,ora_login_user, ??? ora_dict_obj_type,ora_dict_obj_name); END tr_ddl; 例2:创建登录、退出触发器。 CREATE TABLE log_event (user_name VARCHAR2(10), address VARCHAR2(20), logon_date timestamp, logoff_date timestamp); --创建登录触发器 CREATE OR REPLACE TRIGGER tr_logon AFTER LOGON ON DATABASE BEGIN ?? INSERT INTO log_event (user_name,address,logon_date) ?? VALUES (ora_login_user,ora_client_ip_address,systimestamp); END tr_logon; --创建退出触发器 CREATE OR REPLACE TRIGGER tr_logoff BEFORE LOGOFF ON DATABASE BEGIN ?? INSERT INTO log_event (user_name,logoff_date) ?? VALUES (ora_login_user,systimestamp); END tr_logoff; 8.2.5 使用触发器谓词 ??? ORACLE 提供三个参数INSERTING,UPDATING,DELETING 用于判断触发了哪些操作。 谓词 行为 INSERTING 如果触发语句是 INSERT 语句,则为TRUE,否则为FALSE UPDATING 如果触发语句是 UPDATE语句,则为TRUE,否则为FALSE DELETING 如果触发语句是 DELETE 语句,则为TRUE,否则为FALSE 8.2.6 重新编译触发器 (编辑:安卓应用网_ASP源码网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
