zoukankan      html  css  js  c++  java
  • oracle数据库触发器(trigger)用法总结

    from:http://blog.csdn.net/zhanzhib/article/details/48729417

    触发器的意思就是当我们对数据库对象(一般是表或视图)进行insert、update、delete操作的时候,这些操作会相应的触发一些事件的执行,通常要执行的事件被写成PL/SQL程序,那么这些数据库对象上的事件相关的程序就是触发器(trigger)。Oracle数据库中,触发器分为before、after、instead of三种,其中before、after主要对于表操作,instead of主要对于视图操作,因为如果视图是多表的时候,不能直接进行DML操作,这个时候可以建立代替触发器(instead of)来替换事件本身的动作。同时,触发器也可以分为row级和statement级两种,row级的触发器在每次DML一行时执行,statement触发器一个SQL语句引发一次,不管影响几行。

    trigger的触发顺序

    图1:trigger的触发顺序

    上图1非常重要,对于trigger的触发顺序的解释一目了然,尤其是下半副图,update数据的时候,对于statement trigger,不管是before还是after,都只会执行一次,而row trigger,却会在每次的udpate的前后执行一次。

    1、before、after触发器

    创建statement trigger和row trigger的语法直接看下面代码:

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    -- statement级before trigger
    CREATE OR REPLACE TRIGGER secure_emp
      BEFORE INSERT OR DELETE OR UPDATE ON employees
    BEGIN
      IF (TO_CHAR(SYSDATE, 'DY'IN ('SAT''SUN')) OR
         (TO_CHAR(SYSDATE, 'HH24:MI'NOT BETWEEN '08:00' AND '18:00'THEN
        RAISE_APPLICATION_ERROR(-20500,
                                'You may modify EMPLOYEES table only on weekdays.');
      END IF;
    END;
    -- row级before trigger
    CREATE OR REPLACE TRIGGER restrict_salary
      BEFORE INSERT OR UPDATE OF salary ON employees
      FOR EACH ROW
    BEGIN
      IF NOT (:NEW.job_id IN ('AD_PRES''AD_VP')) AND :NEW.salary > 15000 THEN
        RAISE_APPLICATION_ERROR(-20202, 'Error');
      END IF;
    END;
    -- row级after trigger,注意:new和:old的用法
    CREATE OR REPLACE TRIGGER audit_emp_values
      AFTER DELETE OR INSERT OR UPDATE ON employees
      FOR EACH ROW
    BEGIN
      INSERT INTO audit_emp_table
        (user_name,
         TIMESTAMP,
         id,
         old_last_name,
         new_last_name,
         old_title,
         new_title,
         old_salary,
         new_salary)
      VALUES
        (USER,
         SYSDATE,
         :OLD.employee_id,
         :OLD.last_name,
         :NEW.last_name,
         :OLD.job_id,
         :NEW.job_id,
         :OLD.salary,
         :NEW.salary);
    END;
    -- row级before trigger,注意when的用法
    CREATE OR REPLACE TRIGGER derive_commission_pct
      BEFORE INSERT OR UPDATE OF salary ON employees
      FOR EACH ROW
      WHEN (NEW.job_id = 'SA_REP')
    BEGIN
      IF INSERTING THEN
        :NEW.commission_pct := 0;
      ELSIF :OLD.commission_pct IS NULL THEN
        :NEW.commission_pct := 0;
      ELSE
        :NEW.commission_pct := :OLD.commission_pct + 0.05;
      END IF;
    END;

    对于:OLD和:NEW的用法,需要注意的是它们什么时候存在什么时候可用,:old表示引用以前的列值,:new表示引用最新的列值,这两个变量都只能在for each row存在的时候才可用,且update语句:old和:new都有,delete语句只有:old,insert语句只有:new。

    2、instead of触发器

    对于instead of触发器,一般都是用在复杂视图上,用于对复杂视图中相关表的更新操作。如下例所示(代码收录自网络):

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    -- 创建表
    CREATE TABLE STUDENT
    (
       CODE  VARCHAR2(5),
       LNAME VARCHAR2(200)
    )
    CREATE TABLE COURSE
    (
        CODE  VARCHAR2(5),
        CNAME VARCHAR2(30)
    )
    CREATE TABLE ST_CR
    (
       STUDENT VARCHAR2(5),
       COURSE  VARCHAR2(5),
       GRADE   NUMBER
    )
    -- 表的约束
    ALTER TABLE STUDENT ADD CONSTRAINT STUDENT$PK PRIMARY KEY(CODE);
    ALTER TABLE COURSE ADD CONSTRAINT COURSE$PK PRIMARY KEY(CODE);
    ALTER TABLE ST_CR ADD CONSTRAINT ST_CR$PK PRIMARY KEY(STUDENT, COURSE);
    ALTER TABLE ST_CR ADD CONSTRAINT ST_CR$FK$STUDENT FOREIGN KEY(STUDENT) REFERENCES STUDENT(CODE);
    ALTER TABLE ST_CR ADD CONSTRAINT ST_CR$FK$COURSE FOREIGN KEY(COURSE) REFERENCES COURSE(CODE);
    -- 创建基于这三个表的视图
    CREATE OR REPLACE VIEW STUDENT_STATUS AS
       SELECT S.CODE S_CODE, S.LNAME STUDENT, C.CODE C_CODE, C.CNAME COURSE, SC.GRADE GRADE
          FROM STUDENT S, COURSE C, ST_CR SC
            WHERE S.CODE = SC.STUDENT
              AND C.CODE = SC.COURSE
    -- 创建基于视图的instead of触发器
    CREATE OR REPLACE TRIGGER TRI_STCR INSTEAD OF INSERT ON STUDENT_STATUS
       FOR EACH ROW
    DECLARE
      W_ACTION VARCHAR2(1);
    BEGIN
      IF    INSERTING THEN
        W_ACTION := 'I';
      ELSE
        RAISE PROGRAM_ERROR;
      END IF;
        INSERT INTO STUDENT(CODE, LNAME) VALUES(:NEW.S_CODE,:NEW.STUDENT);
        INSERT INTO COURSE(CODE, CNAME) VALUES(:NEW.C_CODE, :NEW.COURSE);
        INSERT INTO ST_CR(STUDENT, COURSE, GRADE)
           VALUES(:NEW.S_CODE, :NEW.C_CODE, :NEW.GRADE);
    END;
    -- 对视图执行数据插入,如果这里没有建过instead of触发器,很明显对复杂视图进行DML操作是会出错的
    INSERT INTO STUDENT_STATUS(S_CODE, STUDENT, C_CODE, COURSE, GRADE)
           VALUES('001','Mike','EN','English',86);

    3、管理Trigger

    1
    2
    3
    4
    ALTER TRIGGER trigger_name DISABLE; -- 失效,生效改为enable
    ALTER TABLE table_name DISABLE ALL TRIGGERS; -- 批量失效,批量生效改为enable
    ALTER TRIGGER trigger_name COMPILE; -- 重新编译trigger
    DROP TRIGGER trigger_name; -- 删除trigger

    oracle数据库中trigger的使用,大概就是这样,虽然看着比较多,但是在实际中确是不太建议使用的,因为维护起来很不方便,所以在能不用trigger的地方还是不用为好。

    2015年01月16日补充:

    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。

     
  • 相关阅读:
    mac 安装 pycharm
    mac clion c/c++环境配置
    CLion201914 下载安装
    mac 安装cmake
    JetBrains CLion 2019 for Mac(智能C和C++编辑器)中英文如何切换完整教程
    SnippetsLab Mac 代码收藏管理工具
    goland 安装破解
    linux管道pipe详解
    HTML meta pragma no-cache 页面缓存
    Connection: close
  • 原文地址:https://www.cnblogs.com/liuqiyun/p/6560035.html
Copyright © 2011-2022 走看看