zoukankan      html  css  js  c++  java
  • PL/SQLTrigger

    --最简单的一个触发器的使用:

    当修改了emp表中的ename字段的时候,假如新值和旧值不同的时候,打印出一条数据

    1 CREATE OR REPLACE TRIGGER EMP_TRI
    2 AFTER UPDATE OF ENAME ON EMP
    3 FOR EACH ROW
    4 WHEN (OLD.ENAME != NEW.ENAME)
    5 BEGIN
    6 DBMS_OUTPUT.PUT_LINE('ename:' || :OLD.ENAME || 'has change to' ||
    7 :NEW.ENAME);
    8 END EMP_TRI;

    存储过程的命名:

    表名_动作_DML操作_行级别
    例:EMP_BEF_UPD(表级别)
    BOOKSHELF_CHECKOUT_BEF_UPD_ROW(行级别)

    1、Hello World的使用

    1 CREATE OR REPLACE TRIGGER D_AFTER_INSERT_hello_world
    2 AFTER INSERT ON D
    3
    4 DECLARE
    5 -- local variables here
    6 BEGIN
    7 DBMS_OUTPUT.PUT_LINE('Hello World');
    8 END T_1;

    2、将输入的小写字母都格式化为大写字母,需要在未存储到数据库的过程中,进行修改,即在BEFORE的时候修改:

    1 create or replace trigger D_BEF_insert_ROW
    2 before insert on d
    3 for each ROW
    4 BEGIN
    5 :NEW.IDS := UPPER(:NEW.IDS);
    6 DBMS_OUTPUT.PUT_LINE('IDS已经变为:' || :NEW.IDS);
    7 END D_BEF_INSERT_ROW;

    3、将对一个表的INSERT/DELETE/UPDATE进行合并:

     1 CREATE OR REPLACE TRIGGER D_AF_IN_UP_DE
    2 AFTER INSERT OR DELETE OR UPDATE ON D
    3 /*
    4 将INSERT和UPDATE、DELETE方法集成在一块,需要使用谓词
    5 INSERTING,UPDATING/DELETING
    6 */
    7 BEGIN
    8 IF INSERTING THEN
    9 DBMS_OUTPUT.PUT_LINE('INSERT');
    10 ELSIF UPDATING THEN
    11 DBMS_OUTPUT.PUT_LINE('UPDATE');
    12 ELSE
    13 DBMS_OUTPUT.PUT_LINE('DELETE');
    14 END IF;
    15 NULL;
    16 END D_AF_IN_UP_DE;

    4、进行修改历史记录的记录:注意在触发器中不可以使用COMMIT,即使在其调用的存储过程中也不可以进行显式的提交。
    当使用在触发器中定义的变量的时候,可以直接使用存储过程名字添加参数名字进行调用,当需要使用:NEW.字段名,需要使用Call关键字:

     1 CREATE OR REPLACE TRIGGER D_AFT_UPDATE_ROW
    2 AFTER UPDATE ON D
    3 FOR EACH ROW
    4 WHEN (NEW.IDS != OLD.IDS)
    5 DECLARE
    6 V_ID VARCHAR2(32);
    7 V_NEW_RECORD D%ROWTYPE;
    8 V_OLD_RECORD D%ROWTYPE;
    9 BEGIN
    10 --进行更新的数据的历史记录
    11 /**
    12 V_ID := SYS_GUID();
    13 INSERT INTO D_LOG
    14 (ID, NEW_VALUE, OLD_VALUE, OP_TIME, CHANGE_COL)
    15 VALUES
    16 (V_ID, :NEW.IDS, :OLD.IDS, SYSDATE, 'd.ids');
    17 DBMS_OUTPUT.PUT_LINE('日志记录成功');
    18 **/
    19 ----------------
    20 V_NEW_RECORD.IDS := :NEW.IDS;
    21 V_OLD_RECORD.IDS := :OLD.IDS;
    22 INSERT_D_LOG(V_NEW_RECORD, V_OLD_RECORD);
    23 EXCEPTION
    24 WHEN OTHERS THEN
    25 DBMS_OUTPUT.PUT_LINE('对不起,出现错误,请检查' || SQLCODE || SQLERRM);
    26 END D_AFT_UPDATE_ROW;

    调用的过程:

    1 --存储过程:
    2 CREATE OR REPLACE PROCEDURE INSERT_D_LOG(I_NEW__REC E%ROWTYPE,I_OLD__REC E%ROWTYPE) IS
    3 BEGIN
    4 --存储记录
    5 INSERT INTO E VALUES I_OLD__REC;
    6 END INSERT_D_LOG;

    5、进行数据的备份,进行数据的拷贝,Maintaining Duplicated Data

    1 create or replace trigger D_AFTER_INSERT_LOG
    2 after insert on d FOR EACH ROW
    3 /**
    4 进行插入数据的备份,将同时存放到D_DUP表中
    5 */
    6 begin
    7 INSERT INTO d_dup VALUES(:new.Ids);
    8 end D_AFTER_INSERT_LOG;

    6、触发器中使用自定义异常。主要是为了防止一些用户删除数据,对对删除数据的时间进行限制,只有非周末时间可以删除数据,
    在这里使用了RAISE_APPLICATION_ERROR procedure, which takes two
    input parameters: the error number (which must be between –20001 and –20999), and the error
    message to be displayed.
    如:RAISE_APPLICATION_ERROR(-20001, '周六和周日不可以删除数据');

    CREATE OR REPLACE TRIGGER D_BEFORE_DELETE
    BEFORE DELETE ON D
    DECLARE
    V_DAY VARCHAR2(100); --日期
    V_USER VARCHAR2(100) := USER; --当前用户
    V_DAY_EXP EXCEPTION;
    V_USER_EXP EXCEPTION;
    BEGIN
    V_DAY := TO_CHAR(SYSDATE, 'DY');
    IF V_DAY = '星期日' OR V_DAY = '星期六' THEN
    RAISE V_DAY_EXP;
    END IF;
    IF V_USER != 'SCOTT' THEN
    RAISE V_USER_EXP;
    END IF;
    EXCEPTION
    WHEN V_DAY_EXP THEN
    RAISE_APPLICATION_ERROR(-20001, '周六和周日不可以删除数据');
    WHEN V_USER_EXP THEN
    RAISE_APPLICATION_ERROR(-20001, '只有SCOTT用户可以删除数据');
    END D_BEFORE_DELETE;

    ----------------------------备注---------------------------------------
    存储过程的命名:
    Naming Triggers
    The name of a trigger should clearly indicate the table it applies to, the DML commands that trigger
    it, its before/after status, and whether it is a row-level or statement-level trigger. Since a trigger name
    cannot exceed 30 characters in length, you need to use a standard set of abbreviations when naming.
    In general, the trigger name should include as much of the table name as possible. Thus, when
    creating a BEFORE UPDATE, row-level trigger on a table named BOOKSHELF_CHECKOUT, you
    should not name the trigger BEFORE_UPDATE_ROW_LEVEL_BC. A better name would be
    BOOKSHELF_CHECKOUT_BEF_UPD_ROW.
    在触发器中调用存储过程;
    Calling Procedures Within Triggers
    Rather than creating a large block of code within a trigger body, you can save the code as a stored
    procedure and call the procedure from within the trigger, by using the call command. For example,
    if you create an INSERT_BOOKSHELF_AUDIT_DUP procedure that inserts rows into BOOKSHELF_
    AUDIT_DUP, you can call it from a trigger on the BOOKSHELF_AUDIT table, as shown in the
    following listing:

     1 CREATE OR REPLACE TRIGGER BOOKSHELF_AFT_INS_ROW
    2 AFTER INSERT ON BOOKSHELF_AUDIT
    3 FOR EACH ROW
    4 BEGIN
    5 CALL INSERT_BOOKSHELF_AUDIT_DUP(:NEW.TITLE,
    6 :NEW.PUBLISHER,
    7 :NEW.CATEGORYNAME,
    8 :NEW.OLD_RATING,
    9 :NEW.NEW_RATING,
    10 :NEW.AUDIT_DATE);
    11 END;

    进行数据的自动备份:建立一个和插入数据的表结构相同的表:例如:user,user_dup,user_dup只是为了记录详细的user信息,
    在user表中建立一个触发器,当插入数据的时候,自动的向user表中插入相同的数据:官方的解释如下:
    (Maintaining Duplicated Data)
    The method of setting values via triggers, shown in the preceding section, can be combined with
    the remote data access methods described in Chapter 25. As with materialized views, you may
    replicate all or some of the rows in a table.
    For example, you may want to create and maintain a second copy of your application’s audit
    log. By doing so, you safeguard against a single application’s erasing the audit log records created
    by multiple applications. Duplicate audit logs are frequently used in security monitoring.
    Consider the BOOKSHELF_AUDIT table used in the examples in this chapter. A second table,
    BOOKSHELF_AUDIT_DUP, could be created, possibly in a remote database. For this example,
    assume that a database link called AUDIT_LINK can be used to connect the user to the database
    in which BOOKSHELF_AUDIT_DUP resides (refer to Chapter 25 for details on database links).
    --建表:
    drop table BOOKSHELF_AUDIT_DUP;
    create table BOOKSHELF_AUDIT_DUP
    (Title VARCHAR2(100),
    Publisher VARCHAR2(20),
    CategoryName VARCHAR2(20),
    Old_Rating VARCHAR2(2),
    New_Rating VARCHAR2(2),
    Audit_Date DATE);
    --
    To automate populating the BOOKSHELF_AUDIT_DUP table, the following trigger could be
    placed on the BOOKSHELF_AUDIT table:

     1 CREATE OR REPLACE TRIGGER BOOKSHELF_AUDIT_AFT_INS_ROW
    2 AFTER INSERT ON BOOKSHELF_AUDIT
    3 FOR EACH ROW
    4 BEGIN
    5 INSERT INTO BOOKSHELF_AUDIT_DUP@AUDIT_LINK
    6 (TITLE, PUBLISHER, CATEGORYNAME, NEW_RATING, AUDIT_DATE)
    7 VALUES
    8 (:NEW.TITLE,
    9 :NEW.PUBLISHER,
    10 :NEW.CATEGORYNAME,
    11 :NEW.NEW_RATING,
    12 :NEW.AUDIT_DATE);
    13 END;
    14 /



    As the trigger header shows, this trigger executes for each row that is inserted into the BOOKSHELF_
    AUDIT table. It inserts a single record into the BOOKSHELF_AUDIT_DUP table in the database
    defined by the AUDIT_LINK database link. AUDIT_LINK may point to a database located on a
    remote server. If there is any problem with the remote insert initiated via the trigger, the local
    insert will fail.
    For asynchronous replication requirements, consider using materialized views instead (see
    Chapter 26).
    You can see the actions of these triggers by inserting a row into BOOKSHELF:
    insert into BOOKSHELF
    (Title, Publisher, CategoryName, Rating) values
    ('HARRY POTTER AND THE CHAMBER OF SECRETS',
    'SCHOLASTIC','CHILDRENFIC','4');
    1 row created.
    select Title from BOOKSHELF_AUDIT;
    TITLE
    ---------------------------------------------------
    HARRY POTTER AND THE CHAMBER OF SECRETS
    select Title from BOOKSHELF_AUDIT_DUP;
    TITLE
    ---------------------------------------------------
    HARRY POTTER AND THE CHAMBER OF SECRETS

    --end

    I believe that we are who we choose to be. Nobody‘s going to come and save you, you‘ve got to save yourself. 我相信我们成为怎样的人是我们自己的选择。没有人会来拯救你,你必须要自己拯救自己。
  • 相关阅读:
    面向对象:
    Android体系结构
    面向对象DAO模式
    集合框架
    异常
    面向对象接口
    面向对象多态
    面向对象继承
    面向对象抽象封装
    JDBC
  • 原文地址:https://www.cnblogs.com/caroline/p/2295131.html
Copyright © 2011-2022 走看看