oracle触发器(下篇)

oracle触发器(下篇)

8.3 删除和使能触发器

l         删除触发器:

DROP   TRIGGER  trigger_name;

当删除其他用户模式中的触发器名称,需要具有DROP ANY TRIGGER系统权限,当删除建立在数据库上的触发器时,用户需要具有ADMINISTER DATABASE TRIGGER系统权限。

此外,当删除表或视图时,建立在这些对象上的触发器也随之删除。 

l         禁用或启用触发器

数据库TRIGGER 的状态:

有效状态(ENABLE):当触发事件发生时,处于有效状态的数据库触发器TRIGGER 将被触发。

无效状态(DISABLE):当触发事件发生时,处于无效状态的数据库触发器TRIGGER 将不会被触发,此时就跟没有这个数据库触发器(TRIGGER) 一样。

数据库TRIGGER的这两种状态可以互相转换。格式为:

ALTER  TIGGER trigger_name  [ DISABLE ENABLE  ] ;

-- 例:ALTER TRIGGER emp_view_delete DISABLE;

           

            ALTER TRIGGER语句一次只能改变一个触发器的状态,而ALTER TABLE语句则一次能够改变与指定表相关的所有触发器的使用状态。格式为:             

ALTER   TABLE   [ schema. ] table_name {ENABLE | DISABLE}  ALL  TRIGGERS;

-- 例:使表EMP 上的所有TRIGGER 失效:
ALTER   TABLE  emp DISABLE  ALL  TRIGGERS; 

 

8.4 触发器和数据字典

相关数据字典:USER_TRIGGERSALL_TRIGGERSDBA_TRIGGERS 

SELECT  TRIGGER_NAME, TRIGGER_TYPE, TRIGGERING_EVENT,
 TABLE_OWNER, BASE_OBJECT_TYPE, REFERENCING_NAMES,
 STATUS, ACTION_TYPE
 
FROM  user_triggers;

 

8.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 = 1000   WHERE  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
      NUMBER;
    BEGIN
      DBMS_OUTPUT.PUT_LINE(
'' 正在执行trig2_insert 触发器… '' );
      SELECT COUNT(*) INTO 
      FROM dept_summary WHERE deptno :new_emp.deptno;
      IF THEN
        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
      NUMBER;
    BEGIN
      DBMS_OUTPUT.PUT_LINE(
'' 正在执行trig2_delete 触发器… '' );
      SELECT emp_count INTO 
      FROM dept_summary WHERE deptno :old_emp.deptno;
      IF >1 THEN
        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.1   WHERE  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提供的条件谓词INSERTINGUPDATINGDELETING创建与例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
            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 
        FROM dept_summary 
        WHERE deptno :new_emp.deptno;
                IF THEN
                    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 
        FROM dept_summary WHERE deptno :old_emp.deptno;
      IF THEN
        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.1   WHERE  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 THEN
                    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 THEN
                    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_ddltrig4_beforetrig4_after触发器,它们调用事件属性函数将各个事件记录到eventlog数据表中。

 

复制代码
BEGIN
    
--  创建用于记录事件日志的数据表
    DBMS_UTILITY.EXEC_DDL_STATEMENT( '
        CREATE TABLE eventlog(
            Eventname VARCHAR2(20) NOT NULL,
            Eventdate date default sysdate,
            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 ALTER OR DROP 
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;
复制代码

 

8.6   数据库触发器的应用实例

用户可以使用数据库触发器实现各种功能:

l         复杂的审计功能;

例:将EMP 表的变化情况记录到AUDIT_TABLEAUDIT_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 
5000  CYCLE;

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 = 25   WHERE  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
    

IF  TO_CHAR(SYSDATE,  ' DAY ' IN  ( ' 星期六 ' ' 星期日 ' THEN
    RAISE not_on_weekends;
END   IF ;
    

SELECT   COUNT ( * INTO   dummy   FROM  company_holidays
    
WHERE  TRUNC( day ) = TRUNC(SYSDATE);
IF   dummy   > 0   THEN
    RAISE not_on_holidays;
END   IF ;
    

IF  (TO_CHAR(SYSDATE, ' HH24 ' ) <</span>8 OR TO_CHAR(SYSDATE, 'HH24')>18THEN
  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 holiday'); 
  
WHEN not_working_hours THEN
    RAISE_APPLICATION_ERROR(
-20326
'May not change employee table during no_working hours'); 
END;
复制代码

 

l         管理复杂的表复制;

l         防止非法的事务发生;

l         自动生成派生的列值;

帮助式显复杂的商业管理。

© 2011  EricHu

原创作品,转贴请注明作者和出处,留此信息。

 

------------------------------------------------

cnBlobs:http://www.cnblogs.com/huyong/
CSDNhttp://blog.csdn.net/chinahuyong 

 

作者:EricHuDBC\SB\SWebServiceWCFPM等)
出处:http://www.cnblogs.com/huyong/

Q Q80368704   E-Mail: 80368704@qq.com
本博文欢迎大家浏览和转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,在『参考』的文章中,我会表明参考的文章来源,尊重他人版权。若您发现我侵犯了您的版权,请及时与我联系。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
oracle触发器实例讲解2008-11-27 09:17--[6]// Oracle Trigger ---------------------------------------------------------------------------------------------// --实例1------------------------ --创建触发器,当用户对test表执行DML语句时,将相关信息记录到日志表 --创建测试表 CREATE TABLE test ( t_id NUMBER(4), t_name VARCHAR2(20), t_age NUMBER(2), t_sex CHAR ); --创建记录测试表 CREATE TABLE test_log ( l_user VARCHAR2(15), l_type VARCHAR2(15), l_date VARCHAR2(30) ); --创建触发器 CREATE OR REPLACE TRIGGER test_trigger AFTER DELETE OR INSERT OR UPDATE ON test DECLARE v_type test_log.l_type%TYPE; BEGIN IF INSERTING THEN --INSERT触发 v_type := 'INSERT'; DBMS_OUTPUT.PUT_LINE('记录已经成功插入,并已记录到日志'); ELSIF UPDATING THEN --UPDATE触发 v_type := 'UPDATE'; DBMS_OUTPUT.PUT_LINE('记录已经成功更新,并已记录到日志'); ELSIF DELETING THEN v_type := 'DELETE'; DBMS_OUTPUT.PUT_LINE('记录已经成功删除,并已记录到日志'); END IF; INSERT INTO test_log VALUES(user,v_type, TO_CHAR(sysdate,'yyyy-mm-dd hh24:mi:ss')); END; / --下面我们来分别执行DML语句 INSERT INTO test VALUES(101,'zhao',22,'M'); UPDATE test SET t_age = 30 WHERE t_id = 101; DELETE test WHERE t_id = 101; --然后查看效果 SELECT * FROM test; SELECT * FROM test_log; --实例2------------------------ --创建触发器,它将映射emp表中每个部门的总人数和总工资 --创建映射表 CREATE TABLE dept_sal AS SELECT deptno,COUNT(empno) AS total_emp,SUM(sal) AS total_sal FROM emp GROUP BY deptno; DESC dept_sal; --创建触发器 CREATE OR REPLACE TRIGGER emp_info AFTER INSERT OR UPDATE OR DELETE ON emp DECLARE CURSOR cur_emp IS SELECT deptno,COUNT(empno) AS total_emp,SUM(sal) AS total_sal FROM emp GROUP BY deptno; BEGIN DELETE dept_sal; --触发时首先删除映射表信息 FOR v_emp IN cur_emp LOOP --DBMS_OUTPUT.PUT_LINE(v_emp.deptno || v_emp.total_emp || v_emp.total_sal); --插入数据 INSERT INTO dept_sal VALUES(v_emp.deptno,v_emp.total_emp,v_emp.total_sal); END LOOP; END; / --对emp表进行DML操作 INSERT INTO emp(empno,deptno,sal) VALUES('123','10',10000); SELECT * FROM dept_sal; DELETE EMP WHERE empno=123; SELECT * FROM dept_sal; --实例3------------------------ --创建触发器,它记录表的删除数据 --创建表 CREATE TABLE employee ( id VARCHAR2(4) NOT NULL, name VARCHAR2(15) NOT NULL, age NUMBER(2) NOT NULL, sex CHAR NOT NULL ); DESC employee; --插入数据 INSERT INTO employee VALUES('e101','zhao',23,'M'); INSERT INTO employee VALUES('e102','jian',21,'F'); --创建记录表 CREATE TABLE old_employee AS SELECT * FROM employee; DESC old_employee; --创建触发器 CREATE OR REPLACE TRIGGER tig_old_emp AFTER DELETE ON employee -- FOR EACH ROW --语句级触发,即每一行触发一次 BEGIN INSERT INTO old_employee VALUES(:old.id,:old.name,:old.age,:old.sex); --:old代表旧值 END; / --下面进行测试 DELETE employee; SELECT * FROM old_employee; --实例4------------------------ --创建触发器,利用视图插入数据 --创建表 CREATE TABLE tab1 (tid NUMBER(4) PRIMARY KEY,tname VARCHAR2(20),tage NUMBER(2)); CREATE TABLE tab2 (tid NUMBER(4),ttel VARCHAR2(15),tadr VARCHAR2(30)); --插入数据 INSERT INTO tab1 VALUES(101,'zhao',22); INSERT INTO tab1 VALUES(102,'yang',20); INSERT INTO tab2 VALUES(101,'13761512841','AnHuiSuZhou'); INSERT INTO tab2 VALUES(102,'13563258514','AnHuiSuZhou'); --创建视图连接两张表 CREATE VIEW tab_view AS SELECT tab1.tid,tname,ttel,tadr FROM tab1,tab2 WHERE tab1.tid = tab2.tid; --创建触发器 CREATE OR REPLACE TRIGGER tab_trigger INSTEAD OF INSERT ON tab_view BEGIN INSERT INTO tab1(tid,tname) VALUES(:new.tid,:new.tname); INSERT INTO tab2(ttel,tadr) VALUES(:new.ttel,:new.tadr); END; / --现在就可以利用视图插入数据 INSERT INTO tab_view VALUES(105,'zhaoyang','13886681288','beijing'); --查看效果 SELECT * FROM tab_view; --实例5------------------------ --创建触发器,比较emp表中更新的工资 CREATE OR REPLACE TRIGGER sal_emp BEFORE UPDATE ON emp FOR EACH ROW BEGIN IF :OLD.sal > :NEW.sal THEN DBMS_OUTPUT.PUT_LINE('工资减少'); ELSIF :OLD.sal < :NEW.sal THEN DBMS_OUTPUT.PUT_LINE('工资增加'); ELSE DBMS_OUTPUT.PUT_LINE('工资未作任何变动'); END IF; DBMS_OUTPUT.PUT_LINE('更新前工资 :' || :OLD.sal); DBMS_OUTPUT.PUT_LINE('更新后工资 :' || :NEW.sal); END; / --执行UPDATE查看效果 UPDATE emp SET sal = 3000 WHERE empno = '7788'; --实例6------------------------ --创建触发器,将操作CREATE、DROP存储在log_info表 --创建表 CREATE TABLE log_info ( manager_user VARCHAR2(15), manager_date VARCHAR2(15), manager_type VARCHAR2(15), obj_name VARCHAR2(15), obj_type VARCHAR2(15) ); --创建触发器 CREATE OR REPLACE TRIGGER trig_log_info AFTER CREATE OR DROP ON SCHEMA BEGIN INSERT INTO log_info VALUES(USER,SYSDATE,SYS.DICTIONARY_OBJ_NAME,SYS.DICTIONARY_OBJ_OWNER, SYS.DICTIONARY_OBJ_TYPE); END; / --测试语句 CREATE TABLE a(id NUMBER); CREATE TYPE aa AS OBJECT(id NUMBER); / DROP TABLE a; DROP TYPE aa; --查看效果 SELECT * FROM log_info; --相关数据字典-----------------------------------------------------// SELECT * FROM USER_TRIGGERS; SELECT * FROM ALL_TRIGGERS; SELECT * FROM DBA_TRIGGERS; --必须以DBA身份登陆才能使用此数据字典 --启用和禁用 ALTER TRIGGER trigger_name DISABLE; ALTER TRIGGER trigger_name ENABLE;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值