23decxf 发表于 2018-9-12 13:06:36

oracle 触发器(下)

  四:总结
  4.1:使用触发器谓词
  ORACLE 提供三个参数INSERTING, UPDATING, DELETING 用于判断触发了哪些操作。
  谓词
  行为
  INSERTING
  如果触发语句是 INSERT 语句,则为TRUE,否则为FALSE
  UPDATING
  如果触发语句是 UPDATE语句,则为TRUE,否则为FALSE
  DELETING
  如果触发语句是 DELETE 语句,则为TRUE,否则为FALSE
4.2:重新编译触发器
  如果在触发器内调用其它函数或过程,当这些函数或过程被删除或修改后,触发器的状态将被标识为无效。当DML语句激活一个无效触发器时,ORACLE将重新编译触发器代码,如果编译时发现错误,这将导致DML语句执行失败。
  在PL/SQL程序中可以调用ALTER TRIGGER语句重新编译已经创建的触发器,格式为:
ALTERTRIGGER trigger_name COMPILE [ DEBUG]  其中:DEBUG 选项要器编译器生成PL/SQL 程序条使其所使用的调试代码。
4.3:删除和使能触发器
  l删除触发器:
DROPTRIGGER trigger_name;  当删除其他用户模式中的触发器名称,需要具有DROP ANY TRIGGER系统权限,当删除建立在数据库上的触发器时,用户需要具有ADMINISTER DATABASE TRIGGER系统权限。
  此外,当删除表或视图时,建立在这些对象上的触发器也随之删除。
  l禁用或启用触发器
  数据库TRIGGER 的状态:
  有效状态(ENABLE):当触发事件发生时,处于有效状态的数据库触发器TRIGGER 将被触发。
  无效状态(DISABLE):当触发事件发生时,处于无效状态的数据库触发器TRIGGER 将不会被触发,此时就跟没有这个数据库触发器(TRIGGER) 一样。
  数据库TRIGGER的这两种状态可以互相转换。格式为:
ALTER TIGGER trigger_name ;--例:ALTER TRIGGER emp_view_delete DISABLE;  ALTER TRIGGER语句一次只能改变一个触发器的状态,而ALTER TABLE语句则一次能够改变与指定表相关的所有触发器的使用状态。格式为:
ALTERTABLEtable_name {ENABLE|DISABLE} ALL TRIGGERS;--例:使表EMP 上的所有TRIGGER 失效:ALTERTABLE emp DISABLE ALL TRIGGERS; 4.4:触发器和数据字典
  相关数据字典:USER_TRIGGERS、ALL_TRIGGERS、DBA_TRIGGERS
SELECT TRIGGER_NAME, TRIGGER_TYPE, TRIGGERING_EVENT,  TABLE_OWNER, BASE_OBJECT_TYPE, REFERENCING_NAMES,
  STATUS, ACTION_TYPE
FROM user_triggers;  4.5:数据库触发器的应用举例
  例1:创建一个DML语句级触发器,当对emp表执行INSERT, UPDATE, DELETE 操作时,它自动更新dept_summary 表中的数据。由于在PL/SQL块中不能直接调用DDL语句,所以,利用ORACLE内置包DBMS_UTILITY中的EXEC_DDL_STATEMENT过程,由它执行DDL语句创建触发器。
CREATE TABLE dept_summary(  
Deptno NUMBER(2),
  
Sal_sum NUMBER(9, 2),
  
Emp_count NUMBER);
  
INSERT INTO dept_summary(deptno, sal_sum, emp_count)
  
SELECT deptno, SUM(sal), COUNT(*)
  
FROM emp
  
GROUP BY deptno;
  
--创建一个PL/SQL过程disp_dept_summary
  
--在触发器中调用该过程显示dept_summary标中的数据。
  
CREATE OR REPLACE PROCEDURE disp_dept_summary
  
IS
  
Rec dept_summary%ROWTYPE;
  
CURSOR c1 IS SELECT * FROM dept_summary;
  
BEGIN
  
OPEN c1;
  
FETCH c1 INTO REC;
  
DBMS_OUTPUT.PUT_LINE('deptno    sal_sum    emp_count');
  
DBMS_OUTPUT.PUT_LINE('-------------------------------------');
  
WHILE c1%FOUND LOOP
  
DBMS_OUTPUT.PUT_LINE(RPAD(rec.deptno, 6)||
  
To_char(rec.sal_sum, '$999,999.99')||
  
LPAD(rec.emp_count, 13));
  
FETCH c1 INTO rec;
  
END LOOP;
  
CLOSE c1;
  
END;
  
BEGIN
  
DBMS_OUTPUT.PUT_LINE('插入前');
  
Disp_dept_summary();
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('
  
CREATE OR REPLACE TRIGGER trig1
  
AFTER INSERT OR DELETE OR UPDATE OF sal ON emp
  
BEGIN
  
DBMS_OUTPUT.PUT_LINE(''正在执行trig1 触发器…'');
  
DELETE FROM dept_summary;
  
INSERT INTO dept_summary(deptno, sal_sum, emp_count)
  
SELECT deptno, SUM(sal), COUNT(*)
  
FROM emp GROUP BY deptno;
  
END;
  
');
  
INSERT INTO dept(deptno, dname, loc)
  
VALUES(90, ‘demo_dept’, ‘none_loc’);
  
INSERT INTO emp(ename, deptno, empno, sal)
  
VALUES(USER, 90, 9999, 3000);
  
DBMS_OUTPUT.PUT_LINE('插入后');
  
Disp_dept_summary();
  
UPDATE emp SET sal=1000WHERE empno=9999;
  
DBMS_OUTPUT.PUT_LINE('修改后');
  
Disp_dept_summary();
  
DELETE FROM emp WHERE empno=9999;
  
DELETE FROM dept WHERE deptno=90;
  
DBMS_OUTPUT.PUT_LINE('删除后');
  
Disp_dept_summary();
  
DBMS_UTILITY.EXEC_DDL_STATEMENT(‘DROP TRIGGER trig1’);
  
EXCEPTION
  
WHEN OTHERS THEN
  
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
  
END;
  例2:创建DML语句行级触发器。当对emp表执行INSERT, UPDATE, DELETE 操作时,它自动更新dept_summary 表中的数据。由于在PL/SQL块中不能直接调用DDL语句,所以,利用ORACLE内置包DBMS_UTILITY中的EXEC_DDL_STATEMENT过程,由它执行DDL语句创建触发器。
BEGIN  
DBMS_OUTPUT.PUT_LINE('插入前');
  
Disp_dept_summary();
  
DBMS_UTILITY.EXEC_DDL_STATEMENT(
  
'CREATE OR REPLACE TRIGGER trig2_update
  
AFTER UPDATE OF sal ON emp
  
REFERENCING OLD AS old_emp NEW AS new_emp
  
FOR EACH ROW
  
WHEN (old_emp.sal != new_emp.sal)
  
BEGIN
  
DBMS_OUTPUT.PUT_LINE(''正在执行trig2_update 触发器…'');
  
DBMS_OUTPUT.PUT_LINE(''sal 旧值:''|| :old_emp.sal);
  
DBMS_OUTPUT.PUT_LINE(''sal 新值:''|| :new_emp.sal);
  
UPDATE dept_summary
  
SET sal_sum=sal_sum + :new_emp.sal - :old_emp.sal
  
WHERE deptno = :new_emp.deptno;
  
END;'
  
);
  
DBMS_UTILITY.EXEC_DDL_STATEMENT(
  
'CREATE OR REPLACE TRIGGER trig2_insert
  
AFTER INSERT ON emp
  
REFERENCING NEW AS new_emp
  
FOR EACH ROW
  
DECLARE
  
I NUMBER;
  
BEGIN
  
DBMS_OUTPUT.PUT_LINE(''正在执行trig2_insert 触发器…'');
  
SELECT COUNT(*) INTO I
  
FROM dept_summary WHERE deptno = :new_emp.deptno;
  
IF I > 0THEN
  
UPDATE dept_summary
  
SET sal_sum=sal_sum+:new_emp.sal,
  
Emp_count=emp_count+1
  
WHERE deptno = :new_emp.deptno;
  
ELSE
  
INSERT INTO dept_summary
  
VALUES (:new_emp.deptno, :new_emp.sal, 1);
  
END IF;
  
END;'
  
);
  
DBMS_UTILITY.EXEC_DDL_STATEMENT(
  
'CREATE OR REPLACE TRIGGER trig2_delete
  
AFTER DELETE ON emp
  
REFERENCING OLD AS old_emp
  
FOR EACH ROW
  
DECLARE
  
I NUMBER;
  
BEGIN
  
DBMS_OUTPUT.PUT_LINE(''正在执行trig2_delete 触发器…'');
  
SELECT emp_count INTO I
  
FROM dept_summary WHERE deptno = :old_emp.deptno;
  
IF I >1THEN
  
UPDATE dept_summary
  
SET sal_sum=sal_sum - :old_emp.sal,
  
Emp_count=emp_count - 1
  
WHERE deptno = :old_emp.deptno;
  
ELSE
  
DELETE FROM dept_summary WHERE deptno = :old_emp.deptno;
  
END IF;
  
END;'
  
);
  
INSERT INTO dept(deptno, dname, loc)
  
VALUES(90, 'demo_dept', 'none_loc');
  
INSERT INTO emp(ename, deptno, empno, sal)
  
VALUES(USER, 90, 9999, 3000);
  
INSERT INTO emp(ename, deptno, empno, sal)
  
VALUES(USER, 90, 9998, 2000);
  
DBMS_OUTPUT.PUT_LINE('插入后');
  
Disp_dept_summary();
  
UPDATE emp SET sal = sal*1.1WHERE deptno=90;
  
DBMS_OUTPUT.PUT_LINE('修改后');
  
Disp_dept_summary();
  
DELETE FROM emp WHERE deptno=90;
  
DELETE FROM dept WHERE deptno=90;
  
DBMS_OUTPUT.PUT_LINE('删除后');
  
Disp_dept_summary();
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TRIGGER trig2_update');
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TRIGGER trig2_insert');
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TRIGGER trig2_delete');
  
EXCEPTION
  
WHEN OTHERS THEN
  
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
  
END;
  例3:利用ORACLE提供的条件谓词INSERTING、UPDATING和DELETING创建与例2具有相同功能的触发器。
BEGIN  
DBMS_OUTPUT.PUT_LINE('插入前');
  
Disp_dept_summary();
  
DBMS_UTILITY.EXEC_DDL_STATEMENT(
  
'CREATE OR REPLACE TRIGGER trig2
  
AFTER INSERT OR DELETE OR UPDATE OF sal
  
ON emp
  
REFERENCING OLD AS old_emp NEW AS new_emp
  
FOR EACH ROW
  
DECLARE
  
I NUMBER;
  
BEGIN
  
IF UPDATING AND :old_emp.sal != :new_emp.sal THEN
  
DBMS_OUTPUT.PUT_LINE(''正在执行trig2 触发器…'');
  
DBMS_OUTPUT.PUT_LINE(''sal 旧值:''|| :old_emp.sal);
  
DBMS_OUTPUT.PUT_LINE(''sal 新值:''|| :new_emp.sal);
  
UPDATE dept_summary
  
SET sal_sum=sal_sum + :new_emp.sal - :old_emp.sal
  
WHERE deptno = :new_emp.deptno;
  
ELSIF INSERTING THEN
  
DBMS_OUTPUT.PUT_LINE(''正在执行trig2触发器…'');
  
SELECT COUNT(*) INTO I
  
FROM dept_summary
  
WHERE deptno = :new_emp.deptno;
  
IF I > 0THEN
  
UPDATE dept_summary
  
SET sal_sum=sal_sum+:new_emp.sal,
  
Emp_count=emp_count+1
  
WHERE deptno = :new_emp.deptno;
  
ELSE
  
INSERT INTO dept_summary
  
VALUES (:new_emp.deptno, :new_emp.sal, 1);
  
END IF;
  
ELSE
  
DBMS_OUTPUT.PUT_LINE(''正在执行trig2触发器…'');
  
SELECT emp_count INTO I
  
FROM dept_summary WHERE deptno = :old_emp.deptno;
  
IF I > 1THEN
  
UPDATE dept_summary
  
SET sal_sum=sal_sum - :old_emp.sal,
  
Emp_count=emp_count - 1
  
WHERE deptno = :old_emp.deptno;
  
ELSE
  
DELETE FROM dept_summary
  
WHERE deptno = :old_emp.deptno;
  
END IF;
  
END IF;
  
END;'
  
);
  
INSERT INTO dept(deptno, dname, loc)
  
VALUES(90, 'demo_dept', 'none_loc');
  
INSERT INTO emp(ename, deptno, empno, sal)
  
VALUES(USER, 90, 9999, 3000);
  
INSERT INTO emp(ename, deptno, empno, sal)
  
VALUES(USER, 90, 9998, 2000);
  
DBMS_OUTPUT.PUT_LINE('插入后');
  
Disp_dept_summary();
  
UPDATE emp SET sal = sal*1.1WHERE deptno=90;
  
DBMS_OUTPUT.PUT_LINE('修改后');
  
Disp_dept_summary();
  
DELETE FROM emp WHERE deptno=90;
  
DELETE FROM dept WHERE deptno=90;
  
DBMS_OUTPUT.PUT_LINE('删除后');
  
Disp_dept_summary();
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TRIGGER trig2');
  
EXCEPTION
  
WHEN OTHERS THEN
  
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
  
END;
  例4:创建INSTEAD OF 触发器。首先创建一个视图myview, 由于该视图是复合查询所产生的视图,所以不能执行DML语句。根据用户对视图所插入的数据判断需要将数据插入到哪个视图基表中,然后对该基表执行插入操作。
DECLARE  
No NUMBER;
  
Name VARCHAR2(20);
  
BEGIN
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('
  
CREATE OR REPLACE VIEW myview AS
  
SELECT empno, ename, ''E''type FROM emp
  
UNION
  
SELECT dept.deptno, dname, ''D''FROM dept
  
');
  
-- 创建INSTEAD OF 触发器trigger3;
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('
  
CREATE OR REPLACE TRIGGER trig3
  
INSTEAD OF INSERT ON myview
  
REFERENCING NEW n
  
FOR EACH ROW
  
DECLARE
  
Rows INTEGER;
  
BEGIN
  
DBMS_OUTPUT.PUT_LINE(''正在执行trig3触发器…'');
  
IF :n.type = ''D''THEN
  
SELECT COUNT(*) INTO rows
  
FROM dept WHERE deptno = :n.empno;
  
IF rows = 0THEN
  
DBMS_OUTPUT.PUT_LINE(''向dept表中插入数据…'');
  
INSERT INTO dept(deptno, dname, loc)
  
VALUES (:n.empno, :n.ename, ''none’’);
  
ELSE
  
DBMS_OUTPUT.PUT_LINE(''编号为''|| :n.empno||
  
''的部门已存在,插入操作失败!'');
  
END IF;
  
ELSE
  
SELECT COUNT(*) INTO rows
  
FROM emp WHERE empno = :n.empno;
  
IF rows = 0THEN
  
DBMS_OUTPUT.PUT_LINE('’向emp表中插入数据…’’);
  
INSERT INTO emp(empno, ename)
  
VALUES(:n.empno, :n.ename);
  
ELSE
  
DBMS_OUTPUT.PUT_LINE(''编号为''|| :n.empno||
  
''的人员已存在,插入操作失败!'');
  
END IF;
  
END IF;
  
END;
  
');
  
INSERT INTO myview VALUES (70, 'demo', 'D');
  
INSERT INTO myview VALUES (9999, USER, 'E');
  
SELECT deptno, dname INTO no, name FROM dept WHERE deptno=70;
  
DBMS_OUTPUT.PUT_LINE('员工编号:'||TO_CHAR(no)||'姓名:'||name);
  
SELECT empno, ename INTO no, name FROM emp WHERE empno=9999;
  
DBMS_OUTPUT.PUT_LINE('部门编号:'||TO_CHAR(no)||'姓名:'||name);
  
DELETE FROM emp WHERE empno=9999;
  
DELETE FROM dept WHERE deptno=70;
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('DROP TRIGGER trig3');
  
END;
  例5:利用ORACLE事件属性函数,创建一个系统事件触发器。首先创建一个事件日志表eventlog,由它存储用户在当前数据库中所创建的数据库对象,以及用户的登陆和注销、数据库的启动和关闭等事件,之后创建trig4_ddl、trig4_before和trig4_after触发器,它们调用事件属性函数将各个事件记录到eventlog数据表中。
BEGIN  
-- 创建用于记录事件日志的数据表
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('
  
CREATE TABLE eventlog(
  
Eventname VARCHAR2(20) NOT NULL,
  
Eventdate date defaultsysdate,
  
Inst_num NUMBER NULL,
  
Db_name VARCHAR2(50) NULL,
  
Srv_error NUMBER NULL,
  
Username VARCHAR2(30) NULL,
  
Obj_type VARCHAR2(20) NULL,
  
Obj_name VARCHAR2(30) NULL,
  
Obj_owner VARCHAR2(30) NULL
  
)
  
');
  
-- 创建DDL触发器trig4_ddl
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('
  
CREATE OR REPLACE TRIGGER trig4_ddl

  
AFTER CREATE OR>  
ON DATABASE
  
DECLARE
  
Event VARCHAR2(20);
  
Typ VARCHAR2(20);
  
Name VARCHAR2(30);
  
Owner VARCHAR2(30);
  
BEGIN
  
-- 读取DDL事件属性
  
Event := SYSEVENT;
  
Typ := DICTIONARY_OBJ_TYPE;
  
Name := DICTIONARY_OBJ_NAME;
  
Owner := DICTIONARY_OBJ_OWNER;
  
--将事件属性插入到事件日志表中
  
INSERT INTO scott.eventlog(eventname, obj_type, obj_name, obj_owner)
  
VALUES(event, typ, name, owner);
  
END;
  
');
  
-- 创建LOGON、STARTUP和SERVERERROR 事件触发器
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('
  
CREATE OR REPLACE TRIGGER trig4_after
  
AFTER LOGON OR STARTUP OR SERVERERROR
  
ON DATABASE
  
DECLARE
  
Event VARCHAR2(20);
  
Instance NUMBER;
  
Err_num NUMBER;
  
Dbname VARCHAR2(50);
  
User VARCHAR2(30);
  
BEGIN
  
Event := SYSEVENT;
  
IF event = ''LOGON''THEN
  
User := LOGIN_USER;
  
INSERT INTO eventlog(eventname, username)
  
VALUES(event, user);
  
ELSIF event = ''SERVERERROR''THEN
  
Err_num := SERVER_ERROR(1);
  
INSERT INTO eventlog(eventname, srv_error)
  
VALUES(event, err_num);
  
ELSE
  
Instance := INSTANCE_NUM;
  
Dbname := DATABASE_NAME;
  
INSERT INTO eventlog(eventname, inst_num, db_name)
  
VALUES(event, instance, dbname);
  
END IF;
  
END;
  
');
  
-- 创建LOGOFF和SHUTDOWN 事件触发器
  
DBMS_UTILITY.EXEC_DDL_STATEMENT('
  
CREATE OR REPLACE TRIGGER trig4_before
  
BEFORE LOGOFF OR SHUTDOWN
  
ON DATABASE
  
DECLARE
  
Event VARCHAR2(20);
  
Instance NUMBER;
  
Dbname VARCHAR2(50);
  
User VARCHAR2(30);
  
BEGIN
  
Event := SYSEVENT;
  
IF event = ''LOGOFF''THEN
  
User := LOGIN_USER;
  
INSERT INTO eventlog(eventname, username)
  
VALUES(event, user);
  
ELSE
  
Instance := INSTANCE_NUM;
  
Dbname := DATABASE_NAME;
  
INSERT INTO eventlog(eventname, inst_num, db_name)
  
VALUES(event, instance, dbname);
  
END IF;
  
END;
  
');
  
END;
  
CREATE TABLE mydata(mydate NUMBER);
  
CONNECT SCOTT/TIGER
  
COL eventname FORMAT A10
  
COL eventdate FORMAT A12
  
COL username FORMAT A10
  
COL obj_type FORMAT A15
  
COL obj_name FORMAT A15
  
COL obj_owner FORMAT A10
  
SELECT eventname, eventdate, obj_type, obj_name, obj_owner, username, Srv_error
  
FROM eventlog;
  
DROP TRIGGER trig4_ddl;
  
DROP TRIGGER trig4_before;
  
DROP TRIGGER trig4_after;
  
DROP TABLE eventlog;
  
DROP TABLE mydata;
数据库触发器的应用实例
  用户可以使用数据库触发器实现各种功能:
  l复杂的审计功能;
  例:将EMP 表的变化情况记录到AUDIT_TABLE和AUDIT_TABLE_VALUES中。
CREATE TABLE audit_table(  
Audit_id   NUMBER,
  
User_name VARCHAR2(20),
  
Now_time DATE,
  
Terminal_name VARCHAR2(10),
  
Table_name VARCHAR2(10),
  
Action_name VARCHAR2(10),
  
Emp_id NUMBER(4));
  
CREATE TABLE audit_table_val(
  
Audit_id NUMBER,
  
Column_name VARCHAR2(10),
  
Old_val NUMBER(7,2),
  
New_val NUMBER(7,2));
  
CREATE SEQUENCE audit_seq
  
START WITH 1000
  
INCREMENT BY 1
  
NOMAXVALUE
  
NOCYCLE NOCACHE;
  
CREATE OR REPLACE TRIGGER audit_emp
  
AFTER INSERT OR UPDATE OR DELETE ON emp
  
FOR EACH ROW
  
DECLARE
  
Time_now DATE;
  
Terminal CHAR(10);
  
BEGIN
  
Time_now:=sysdate;
  
Terminal:=USERENV('TERMINAL');
  
IF INSERTING THEN
  
INSERT INTO audit_table
  
VALUES(audit_seq.NEXTVAL, user, time_now,
  
terminal, 'EMP', 'INSERT', :new.empno);
  
ELSIF DELETING THEN
  
INSERT INTO audit_table
  
VALUES(audit_seq.NEXTVAL, user, time_now,
  
terminal, 'EMP', 'DELETE', :old.empno);
  
ELSE
  
INSERT INTO audit_table
  
VALUES(audit_seq.NEXTVAL, user, time_now,
  
terminal, 'EMP', 'UPDATE', :old.empno);
  
IF UPDATING('SAL') THEN
  
INSERT INTO audit_table_val
  
VALUES(audit_seq.CURRVAL, 'SAL', :old.sal, :new.sal);
  
ELSE UPDATING('DEPTNO')
  
INSERT INTO audit_table_val
  
VALUES(audit_seq.CURRVAL, 'DEPTNO', :old.deptno, :new.deptno);
  
END IF;
  
END IF;
  
END;
  l增强数据的完整性管理;
  例:修改DEPT表的DEPTNO列时,同时把EMP表中相应的DEPTNO也作相应的修改;
CREATE SEQUENCE update_sequence  
INCREMENT BY 1
  
START WITH 1000
  
MAXVALUE 5000CYCLE;
  
ALTER TABLE emp
  
ADD update_id NUMBER;
  
CREATE OR REPLACE PACKAGE integritypackage AS
  
Updateseq NUMBER;
  
END integritypackage;
  
CREATE OR REPLACE PACKAGE BODY integritypackage AS
  
END integritypackage;
  
CREATE OR REPLACE TRIGGER dept_cascade1
  
BEFORE UPDATE OF deptno ON dept
  
DECLARE
  
Dummy NUMBER;
  
BEGIN
  
SELECT update_sequence.NEXTVAL INTO dummy FROM dual;
  
Integritypackage.updateseq:=dummy;
  
END;
  
CREATE OR REPLACE TRIGGER dept_cascade2
  
AFTER DELETE OR UPDATE OF deptno ON dept
  
FOR EACH ROW
  
BEGIN
  
IF UPDATING THEN
  
UPDATE emp SET deptno=:new.deptno,
  
update_id=integritypackage.updateseq
  
WHERE emp.deptno=:old.deptno AND update_id IS NULL;
  
END IF;
  
IF DELETING THEN
  
DELETE FROM emp
  
WHERE emp.deptno=:old.deptno;
  
END IF;
  
END;
  
CREATE OR REPLACE TRIGGER dept_cascade3
  
AFTER UPDATE OF deptno ON dept
  
BEGIN
  
UPDATE emp SET update_id=NULL
  
WHERE update_id=integritypackage.updateseq;
  
END;
  
SELECT * FROM EMP ORDER BY DEPTNO;
  
UPDATE dept SET deptno=25WHERE deptno=20;
  l帮助实现安全控制;
  例:保证对EMP表的修改仅在工作日的工作时间;
CREATE TABLE company_holidays(day DATE);  
INSERT INTO company_holidays
  
VALUES(sysdate);
  
INSERT INTO company_holidays
  
VALUES(TO_DATE('21-10月-01', 'DD-MON-YY'));
  
CREATE OR REPLACE TRIGGER emp_permit_change
  
BEFORE INSERT OR DELETE OR UPDATE ON emp
  
DECLARE
  
Dummy NUMBER;
  
Not_on_weekends EXCEPTION;
  
Not_on_holidays EXCEPTION;
  
Not_working_hours EXCEPTION;
  
BEGIN
  
/* check for weekends */
  
IF TO_CHAR(SYSDATE, 'DAY') IN ('星期六', '星期日') THEN
  
RAISE not_on_weekends;
  
END IF;
  
/* check for company holidays */
  
SELECT COUNT(*) INTO dummy FROM company_holidays
  
WHERE TRUNC(day)=TRUNC(SYSDATE);
  
IF dummy >0THEN
  
RAISE not_on_holidays;
  
END IF;
  
/* check for work hours(8:00 AM to 18:00 PM */
  
IF (TO_CHAR(SYSDATE,'HH24')18) THEN
  
RAISE not_working_hours;
  
END IF;
  
EXCEPTION
  
WHEN not_on_weekends THEN
  
RAISE_APPLICATION_ERROR(-20324,
  
'May not change employee table during the weekends');
  
WHEN not_on_holidays THEN
  
RAISE_APPLICATION_ERROR(-20325,
  
'May not change employee table during a holiday');
  
WHEN not_working_hours THEN
  
RAISE_APPLICATION_ERROR(-20326,
  
'May not change employee table during no_working hours');
  
END;
  l管理复杂的表复制;
  l防止非法的事务发生;
  l自动生成派生的列值;
  帮助式显复杂的商业管理。
  转载:
  http://www.cnblogs.com/huyong/archive/2011/04/27/2030466.html


页: [1]
查看完整版本: oracle 触发器(下)