触发器执行顺序
在同一个对象上可以作用多个触发器,因此触发器被激活是有先后顺序的:
- 首先触发的是前语句级触发器(before statement trigger),该触发器执行一次
- 如果有行级的触发器则接下来执行前行级触发器(before row trigger)该触发器域SQL修改的记录次数一致
- 当SQL修改记录完成后会触发行级触发器,这是的行级触发器为后触发(after statement trigger),该类型触发的次数同SQL修改记录的次数一致
- 执行一次语句级的触发器,此时的语句级的出嘎旗为后与狙击触发器(after statement trigger)
如果相同类型,相同事件触发器作用在同一个对象上,如果在Oracle 11g之前,那么最终被执行的会有一定的随机性,在Oracle 11g中利用FOLLOWS可以控制其顺序
CREATE TRIGGER PRODUCTINFO_OPER_ORD_TGR
BEFORE INSERT
ON PRODUCTINFO
FOR EACH ROW
FOLLOWS PRODUCTINFO_OPER_TGR
BEGIN
DBMS_OUTPUT.PUT_LINE('触发器顺序测试');
END;
符合类型触发器
复合类型触发器是Oracle 11g 的新特性,属于触发器的增强部分。复合类型的触发器相当于在一个触发器中包含了4种不同类型的触发器,分别是语句之前(before statement),行之前(before row),语句之后(after statement).这么做可以很轻松地把变量在各状态之间传递
利用该类型的触发器还可以很方便地解决ORA-04091错误,这里涉及一个变异表的概念,读者可以理解变异表是正在被DML操作修改的表,也是触发器的作用表,而触发器通常不能对变异表进行操作,下面一个示例将利用复合类型的触发器,解决ORA-04091错误
--当productinfo表中的数据提高价格时,触发器判断新旧价格差是否高于价格在2000以下的所有产品价格的平均值的20%,如果高于此值,则提示数据有问题
CREATE OR REPLACE TRIGGER COMPOUND_TGR
FOR UPDATE ON PRODUCTINFO COMPOUND TRIGGER
V_PRO_AVG NUMBER(10,2) := 0.0;
BEFORE STATEMENT IS
BEGIN
SELECT AVG(PRODUCTPRICE)
INTO V_PRO_AVG
FROM PRODUCTINFO
WHERE PRODUCTINFO.PRODUCTPRICE < 2000;
END BEFORE STATEMENT;
AFRER EACH ROW IS
BEGIN
IF :NEW.PRODUCTPRICE - :OLD.PRODUCTPRICE > V_PRO_AVG * 0.20 THEN
RAISE_APPLICATION_ERROR(-20011,'数据修改错误!');
END IF;
END AFTER EACH ROW;
END;
INSTEAD OF 类型触发器
在该类型的触发器作用下,如果对作用对象执行DML操作,那么该操作会被触发器的内部操作所取代。触发器作用在视图当中,用于解决视图不可更新的问题。至于什么样的视图不可更新
--利用INSTEAD OF触发器的使用
--step1,创建视图
CREATE VIEW PRODUCTINFO_VIEW AS --视图
SELECT DISTINCT PRODUCTNAME,PRODUCTPRICE,QUANTITY,CATEGORY,ORIGIN
FROM PRODUCTINFO;
--STEP2 创建触发器
CREATE TRIGGER INSTEAD_OF_TGR
INSTEAD OF INSERT ON PRODUCTINFO_VIEW
DECLARE
CATEGID VARCHAR2(10);
BEGIN
SELECT CATEGROYID
INTO CATEGID
FROM CATEGROYINFO
WHERE CATEGROYINFO.CATEGROYNAME = :NEW.CATEGORY;
DBMS_OUTPUT.PUT_LINE('------' || CATEGID);
INSERT INTO PRODUCTINFO
VALUES
('0240090001',
:NEW.PRODUCTNAME,
:NEW.PRODUCTPRICE,
:NEW.QUANTITY,
CATEGID,
'测试',
:NEW,ORIGIN
);
END;
DDL类型触发器
--该触发器将提示create创建操作,如果有人执行test表的删除操作,提示错误,也不允许对表使用alter操作和rename操作
CREATE TRIGGER DDL_TGR
BEFORE CREATE OR ALTER OR DROP OR RENAME ON SCHEMA
BEGIN
IF SYSEVENT = 'CREATE' THEN
--SYSEVENT 事件属性,当前操作
DBMS_OUTPUT.PUT_LINE(DICTIONARY_OBJ_NAME || '创建中...');
ELSEIF SYSEVENT = 'DROP' THEN
IF DICTIONARY_OBJ_NAME = 'TEST' THEN
--DICTIONARY_OBJ_NAME ,操作的对象名称
RASIE_APPLICATION_ERROR(-20000,'');
END IF;
ELSEIF SYSEVENT = 'ALTER' THEN
RASIE_APPLICATION_ERROR(-20000,'不允许修改表!');
ELSEIF SYSEVENT = 'RENAME' THEN
RASIE_APPLICATION_ERROR(-20000,'不允许修改表名称!');
END IF;
END;
用户和系统事件触发器
所谓的系统触发器,就是基于Oracle系统事件而建立的触发器,该类型的触发器可以审计数据库的登录,注销以及关闭和启动
--step1 创建用户登录日志表
CREATE TABLE LOG_USER (
LOGONID VARCHAR2(50),
LOGONNAME VARCHAR2(50),
LOGONTIME DATE,
CONSTRAINT LOG_USER_PRK PRIMARY KEY (LOGONID)
);
--STEP2 创建触发器,该触发器是数据库级,记录每个用户的登录时间
CREATE TRIGGER LOGON_TGR
AFTER
LOGON
ON DATABASE
BEGIN
INSERT INTO LOG_USER
VALUES(LOG_TAB_ID.NEXTVAL,SYS.LOGIN_USER,SYSDATE);
END;
删除触发器
DROP TRIGGER DEV_TGR