第11章 觸發(fā)器

target

了解什么是觸發(fā)器
了解觸發(fā)器的作用及觸發(fā)器的類型
掌握觸發(fā)器的創(chuàng)建
掌握觸發(fā)器的修改及查看

1. 什么是觸發(fā)器

學習存儲過程后,認識和了解觸發(fā)器并不復(fù)雜,它們之間有著相似之處。

1.1 認識觸發(fā)器

觸發(fā)器和存儲過程比較類似,它由PL/SQL編寫并存儲在數(shù)據(jù)庫中,它可以調(diào)用存儲過程,但觸發(fā)器本身的調(diào)用和存儲過程調(diào)用卻是不一樣的。

存儲過程由用戶、應(yīng)用程序、觸發(fā)器或其他過程調(diào)用。但觸發(fā)器只能由數(shù)據(jù)庫的特定事件來觸發(fā)。所謂的特定事件主要包括如下幾種類型的事件。

(1) 用戶在指定的表或視圖中做DML操作,主要包括如下幾種:

  • INSERT操作,在特定的表或視圖中増加數(shù)據(jù)。
  • UPDATE操作,對特定的表或視圖修改數(shù)據(jù)。
  • DELETE操作,刪除特定表或視圖的數(shù)據(jù)。

(2) 用戶做DDL操作,主要包括如下幾種:

  • CREATE操作,創(chuàng)建對象。
  • ALTER操作,修改對象。
  • DROP操作,刪除對象。

(3) 數(shù)據(jù)庫事件,主要包括如下幾種:

  • LOGON/LOGOFF用戶的登錄或注銷。
  • STARTUP/SHUTDOWN數(shù)據(jù)庫的打開或關(guān)閉?
  • ERRORS特定的錯誤消息等。

在以上事件中的一種或多種發(fā)生時就能使觸發(fā)器運行。

??:當員工表中新增一條記錄后,自動打印“成功插入新員工”

create or replace trigger insertStaffHint
 after insert on emp_temp 
 for each row
declare

begin

 dbms_output.put_line('新增員工成功');

end insertStaffHint;
/

測試:

SQL> set serveroutput on;
SQL> insert into emp_temp(empno,ename,job,sal,deptno) values(20,'韓梅梅','boss',12345,10);
新增員工成功

已創(chuàng)建 1 行。

1.2 觸發(fā)器的作用

觸發(fā)器可以根據(jù)不同的事件進行調(diào)用,它有著更加精細的控制能力,這種特性可以幫助開 發(fā)人員完成很多普通PL/SQL語句完成不了的功能。

  • 自動生成自增長字段。例如,在表中插入數(shù)據(jù)前得到序列的最大值,避免序列重復(fù)。

  • 執(zhí)行更復(fù)雜的業(yè)務(wù)邏輯。

  • 防止無意義的數(shù)據(jù)操作。利用觸發(fā)器可以把符合某些條件的數(shù)據(jù)加以限制,使其不能變動。

  • 提供審計。利用觸發(fā)器可以跟蹤對數(shù)據(jù)庫的操作,也可以在指定的表或視圖記錄改變時,利用觸發(fā)器把數(shù)據(jù)變動日志記錄下來。

  • 允許或限制修改某些表。利用觸發(fā)器可以限制表的變動。

  • 實現(xiàn)完整性規(guī)則。當一個表中的數(shù)據(jù)有變動時可以利用觸發(fā)器修改這些變動數(shù)據(jù)在其他表中的關(guān)聯(lián)數(shù)據(jù)(正常情況下可以利用外鍵進行限制)。

  • 保證數(shù)據(jù)的同步復(fù)制。

建議開發(fā)人員只在必要時使用觸發(fā)器,因為觸發(fā)器可能造成比較雜的相關(guān)依賴性, 注意這種情況在大型的數(shù)據(jù)庫中可能會帶來麻煩。

1.3 觸發(fā)器的類型

觸發(fā)器可分為5種類型,具體內(nèi)容如下:

  • 數(shù)據(jù)操縱語言(DML)觸發(fā)器。

    此種類型觸發(fā)器定義到表上,當對表執(zhí)行INSERT、 UPDATE、DELETE操作時可以激發(fā)該類型的觸發(fā)器。利用該類觸發(fā)器可以復(fù)制、檢査、 替換某種符合指定條件的數(shù)據(jù)。

    按照觸發(fā)級別可以分為兩種方式:

    • 第一種為行級觸發(fā)器,此種類型表示每條記錄修改時都會激發(fā)該觸發(fā)器。
    • 第二種為語句級觸發(fā)器,此種類型表示當SQL語句執(zhí)行時會激發(fā)該觸發(fā)器,與修改多少條記錄沒有關(guān)系。

    按照數(shù)據(jù)的更改事件為準,則分為:

    • BEFORE
    • AFTER
  • 數(shù)據(jù)定義語言(DDL)觸發(fā)器。

    當CREATE、ALTER、DROP模式對象時會觸發(fā)相關(guān)的觸發(fā)器,在Oracle中可以簡單地理解一個用戶就有一個和它同名的模式,利用它可以使得某些表不能被修改或刪除。

  • 復(fù)合觸發(fā)器。此種類型的觸發(fā)器是Oracle 11g的新特性,它相當于在一個觸發(fā)器中包含 了4種類型的觸發(fā)器,其中包含了BEFORE類型的語句級、BEFORE類型的行級、 AFTER類型的語句級、AFTER類型的行級。這種把所有觸發(fā)器都放到一個代碼塊中的 做法使得變量的傳遞變得更加方便。

  • INSTEAD OF觸發(fā)器。此種類型觸發(fā)器通常作用在視圖上。對由多個源表的視圖做 DML操作通常是不被允許的,如果遇到這種情況就可以利用INSTEAD OF類型觸發(fā)器 解決問題。利用它可以把對視圖的DML操作轉(zhuǎn)換成對多個源表進行操作。

  • 用戶和系統(tǒng)事件觸發(fā)器。作用在數(shù)據(jù)庫上由數(shù)據(jù)庫事件激發(fā)的觸發(fā)器,如登錄和注銷 事件的觸發(fā)器。利用它可以記錄數(shù)據(jù)庫的登錄情況。

1.4 觸發(fā)器的語法

(1) DML觸發(fā)器語法

CREATE [ OR REPLACE ] TRIGGER [schema.] trigger 
    {BEFORE | AFTER | INSTEAD OF}
    {DELETE | INSERT | UPDATE
            [OF column (, column ]...]
    }
    [OR {DELETE | INSERT | UPDATE
          [OF column [,column]...]
        }
    ]...
  {ON [schema. ]table | [schema.] view}
    [FOR EACH ROW ]
    [FOLLOWS [schema.] trigger [, [ schema. ] trigger ]...] 
    [ENABLE | DISABLE]
      [WHEN (condition)]
    trigger_body

【語法說明】

  • OR REPLACE:新建的觸發(fā)器可以覆蓋原有同名觸發(fā)器。
  • TRIGGER:創(chuàng)建觸發(fā)器的關(guān)鍵詞。
  • schema:觸發(fā)器所屬模式(可簡單看成用戶名),如果不加該項則表示該觸發(fā)器屬于自己。
  • BEFORE:觸發(fā)器類型為前觸發(fā)。
  • AFTER:觸發(fā)器類型為后觸發(fā)。
  • INSTEAD OF:表示觸發(fā)器類型為替換類型。
  • DELETE I INSERT I UPDATE:表示觸發(fā)的事件。
  • [ OF column [.column ]:觸發(fā)條件具體到的某列。
  • ON [ schema. ] table I [ schema. ] view:該觸發(fā)器作用的表或視圖,INSTEAD OF類型可 以作用在視圖上。
  • FOR EACH ROW:表示行級觸發(fā)器,省略則為語句級觸發(fā)器。
  • FOLLOWS [ schema. ] trigger:觸發(fā)器執(zhí)行的順序。
  • ENABLE I DISABLE:設(shè)置觸發(fā)器是否可用狀態(tài)。
  • WHEN (condition):觸發(fā)該觸發(fā)器的條件。
  • trigger_body:表示觸發(fā)器的函數(shù)體。

(2) DDL和數(shù)據(jù)庫事件觸發(fā)器語法

create [or replace] trigger [schema.] trigger
    { BEFORE | AFTER }
    { ddl_event [OR ddl_event]...
    | database_event [OR database_event]...
    }
    
    ON { [schema.] SCHEMA
        | DATABASE
        }
    [FOLLWS [schema.] trigger [,[schema.] trigger ]...]
    [ENABLE | DISABLE]
    [WHEN (condition)]
    trigger_body

【語法說明】

  • OR REPLACE;新建的觸發(fā)器可以覆蓋原有同名觸發(fā)器。
  • TRIGGER:創(chuàng)建觸發(fā)器的關(guān)鍵詞。
  • schema:觸發(fā)器所屬模式,如果不加該項則表示該觸發(fā)器屬于自己。
  • BEFORE:觸發(fā)器類型為前觸發(fā)。
  • AFTER:觸發(fā)器類型為后觸發(fā)。
  • ddl.event |OR ddl_event]: DDL事件,用OR連接
  • database_event[OR database_event|:數(shù)據(jù)庫事件,用OR連接。
  • [schema.] SCHEMA I DATABASE:觸發(fā)器可作用在模式上或數(shù)據(jù)庫上。
  • FOLLOWS [ schema. ] trigger:觸發(fā)器執(zhí)行的順序。
  • ENABLE I DISABLE;設(shè)置觸發(fā)器是否可用狀態(tài)。
  • WHEN (condition):觸發(fā)該觸發(fā)器的條件。
  • trigger_body:表示觸發(fā)器的函數(shù)體。

部門DDL事件:

DDL事件 簡介
ALTER 修改對象,例如修改對象的名稱約束等
ANALYSE 用來分析統(tǒng)計信息
AUDIT/NOAUDIT 啟用或取消審計
COMMENT 注解列或表的含義
CREATE 創(chuàng)建對象
DROP 刪除對象
GRANT 授權(quán)操作
RENAME 修改對象名稱
REVOKE 取消授權(quán)
TRUNCATE 刪除整張表的行記錄

數(shù)據(jù)庫事件列表:

數(shù)據(jù)庫事件 簡介
STARTUP 數(shù)據(jù)庫打開后被觸發(fā),模式下不可以
SHUTDOWN 數(shù)據(jù)庫關(guān)閉前被觸發(fā),模式下不可以
LOGON 客戶程序登錄后觸發(fā)
LOGOFF 客戶程序注銷前觸發(fā)
SERVERERROR 錯誤消息出現(xiàn)后觸發(fā)

(3) 復(fù)合觸發(fā)器語法

CREATE [OR REPLACE] TRIGGER schema.] trigger    
    FOR
    { DELETE | INSERT | UPDATE      
        [OF column [, column ]...]
  }

    [OR {DELETE | INSERT | UPDATE   
            [OF column (,   column]... ]    
        }   
  ]...
 
  ON {(schema.]table            
         | [schema.] view       
     }

    COMPOUND TRIGGER            
    { BEFORE STATEMENT  IS tps_body END BEFORE STATEMENT]   
    | BEFORE EACH ROW   IS tps_body END BEFORE EACH ROW 
    | AFTER STATEMENT   S tps body END AFTER STATEMENT  
    | AFTER EACH ROW    S tps_body END AFTER EACH ROW   
    }   

【語法說明】

  • OR REPLACE:新建的觸發(fā)器可以覆蓋原有同名觸發(fā)器。
  • TRIGGER:創(chuàng)建觸發(fā)器的關(guān)鍵詞。
  • schema:觸發(fā)器所屬模式,如果不加該項則表示該觸發(fā)器屬于自己。
  • DELETE | INSERT | UPDATE:表示觸發(fā)事件。
  • COMPOUND TRIGGER:定義觸發(fā)器時表示為復(fù)合類型觸發(fā)器。
  • BEFORE STATEMENT:前語句級觸發(fā)。
  • BEFORE EACH ROW:前行級觸發(fā)。
  • AFTER STATEMENT:后語句級觸發(fā)。
  • AFTER EACH ROW:后行級觸發(fā)。
  • tps_body:具體語句或程序。

2. 利用SQL*Plus創(chuàng)建觸發(fā)器

2.1 創(chuàng)建觸發(fā)器

用戶模式下如果想在自己的對象上創(chuàng)建觸發(fā)器, 則必須具有CREATE TRIGGER系統(tǒng)權(quán)限,如果想在其他用戶上創(chuàng)建觸發(fā)器,則需要有CREATE ANY TRIGGER權(quán)限。

除此之外,如果在數(shù)據(jù)庫上創(chuàng)建觸發(fā)器,則需要有ADMINISTER DATABASE TRIGGER系統(tǒng)權(quán)限。

??:刪除emp_temp表時觸發(fā)

create trigger emp_tri
    --觸發(fā)類型為后觸發(fā),觸發(fā)事件是刪除操作,作用在emp_temp表上
    after delete on emp_temp
    
begin
    if deleting then
        dbms_output.put_line('刪除數(shù)據(jù)操作');
    end if;
end;
/

測試:

SQL> delete from emp_temp where empno = 20;
刪除數(shù)據(jù)操作

已刪除 1 行。

2.2 查看觸發(fā)器

(1) 查看觸發(fā)器名稱

select object_name from user_objects
where object_type = 'TRIGGER';

(2) 查看觸發(fā)器內(nèi)容

select * from user_source where name='EMP_TRI' order by line;

2.3 DML類型觸發(fā)器

dml類型觸發(fā)器在日常開發(fā)中比較常用。

當在 productinfo 表中增加數(shù)據(jù)時將觸發(fā)該觸發(fā)器,并把所做的操作記錄到表 option_log 中。

① 創(chuàng)建操作事件記錄表

字段名 注釋 數(shù)據(jù)類型
id 記錄id,主鍵 varchar2(10)
oper_table 被操作的表名 varchar2(20)
oper_table_prk 被操作表的主鍵 varchar2(50)
oper_kd 操作類型 varchar2(10)
oper_date 操作時間 date

SQL:

create table log_tab(
    id varchar2(10),
  oper_table varchar2(20),
  oper_table_prk varchar2(50),
  oper_kd varchar2(10),
  oper_date date
);

② 創(chuàng)建用作 log_tab 表主鍵的自增長序列

create sequence log_tab_id
    minvalue 1
    maxvalue 999999999
    start with 1
    increment by 1
/

(1) 創(chuàng)建行級觸發(fā)器

create or replace trigger productinfo_oper_tgr
    --當productinfo表insert之前觸發(fā)
    before insert on productinfo
        for each row
        
begin
    if inserting then
        insert into log_tab values(log_tab_id.nextval,'productinfo','insert',:new.productid,sysdate);
    end if;
end;
/

行級觸發(fā)器里使用:new:old來訪問變更前和變更后的數(shù)據(jù)。其中:

  • 如果增加的是新紀錄操作,則只有:new可以訪問。
  • 如果是修改操作,則:new:old都可以訪問,:new表示修改后的數(shù)據(jù),:old表示修改前的數(shù)據(jù)。
  • 如果是刪除操作,只有:old可以訪問,因為該操作是刪除已有的記錄。

驗證觸發(fā)器:

insert into productinfo values('10','榮耀pad',2000,'平板',100,'鄭州','');

會發(fā)現(xiàn),productinfo插入一條數(shù)據(jù)后,log_tab表中也會插入一條記錄。

(2) 多種觸發(fā)事件

create trigger productinfo_oper_dml_tgr
    after insert or update or delete 
    on productinfo
    for each row

begin
    case
        --增加操作
        when inserting then
            insert into log_tab values(log_tab_id.nextval,'productinfo','insert',:new.productid,sysdate);
            dbms_output.put_line('插入數(shù)據(jù)完成,主鍵是:' || :new.productid);
            
        --更新操作
        when updating then
            insert into log_tab values(log_tab_id.nextval,'productinfo','update',:old.productid,sysdate);
            dbms_output.put_line('更新數(shù)據(jù)完成,主鍵是:' || :old.productid);
    
    --刪除操作
        when deleting then
            insert into log_tab values(log_tab_id.nextval,'productinfo','delete',:old.productid,sysdate);
            dbms_output.put_line('刪除數(shù)據(jù)完成,主鍵是:' || :old.productid);
            
    end case;
end;
/

驗證觸發(fā)器:

  1. 增加一條數(shù)據(jù):

    SQL> insert into productinfo values('11','榮耀10',2400,'手機',80,'臺灣','');
    插入數(shù)據(jù)完成,主鍵是:11
    
    已創(chuàng)建 1 行。
    
  2. 修改數(shù)據(jù):

    SQL> update productinfo set DESCRIPTION = 'test' where productid in (7,8);
    更新數(shù)據(jù)完成,主鍵是:7
    更新數(shù)據(jù)完成,主鍵是:8
    
    已更新2行。
    
  3. 刪除數(shù)據(jù):

    SQL> delete from productinfo where productid = '11';
    刪除數(shù)據(jù)完成,主鍵是:11
    

(3) 在觸發(fā)器中使用if

如果修改的日期是25日,并且修改產(chǎn)品的價格高于3000,那么修改將終止。

create or replace trigger productinfo_oper_chk_tgr
    before update of productprice on productinfo
    for each row
begin
    if (to_char(sysdate,'dd') = 25 and :old.productprice > 3000) then
        raise_application_error(-20000,'今天是25日,不能修改價格高于3000的數(shù)據(jù)!');
    end if;
    insert into log_tab values (log_tab_id.nextval,'productinfo','insert',:new.productid,sysdate);
    
    dbms_output.put_line('修改數(shù)據(jù)完成,主鍵是:' || :new.productid);
end;
/

(4) 使用when限制條件

當在表 productinfo 中增加的數(shù)據(jù)是”顯示器“類型時,需要把當前價格打九折

create or replace trigger productinfo_when_oper_tgr
    before insert on productinfo 
    for each row
    when (new.category = '顯示器')
begin
    dbms_output.put_line('原價格:' || :new.productprice);
    :new.productprice := :new.productprice * 0.9;
    dbms_output.put_line('現(xiàn)價格:' || :new.productprice);
end;
/

驗證觸發(fā)器:

SQL> insert into productinfo values('11','榮耀顯示器',4599,'顯示器',90,'鄭州','無');
原價格:4599
現(xiàn)價格:4139.1
插入數(shù)據(jù)完成,主鍵是:11

已創(chuàng)建 1 行。

SQL> insert into productinfo values('12','華為matepad',4599,'平板',10,'鄭州','無');
插入數(shù)據(jù)完成,主鍵是:12

已創(chuàng)建 1 行。

2.4 DDL類型觸發(fā)器

所謂DDL類型觸發(fā)器,就是因DDL操作而激發(fā)的觸發(fā)器,主要包括CREATE、ALTER、 DROP等事件

create or replace trigger ddl_tgr
    before create or alter or drop or rename on schema
begin
    if sysevent = 'CREATE' then
        dbms_output.put_line(dictionary_obj_name || '創(chuàng)建中...');
    elsif sysevent = 'DROP' then
        if dictionary_obj_name = 'TEST' then
            raise_application_error(-20000,'不允許刪除Test表');
        end if;
    elsif sysevent = 'ALTER' then
        raise_application_error(-20000,'不允許修改表');
    elsif sysevent = 'RENAME' then
        raise_application_error(-20000,'不允許修改表名');
    end if;
end;
/

驗證觸發(fā)器:

SQL> create table test(
  2  id number
  3  );
TEST創(chuàng)建中...

表已創(chuàng)建。


SQL> rename test to test;
rename test to test
*
第 1 行出現(xiàn)錯誤:
ORA-00604: 遞歸 SQL 級別 1 出現(xiàn)錯誤
ORA-20000: 不允許修改表名
ORA-06512: 在 line 11


SQL> drop table test;
drop table test
*
第 1 行出現(xiàn)錯誤:
ORA-00604: 遞歸 SQL 級別 1 出現(xiàn)錯誤
ORA-20000: 不允許刪除Test表
ORA-06512: 在 line 6

常用事件屬性:

屬性函數(shù) 可用的事件 簡介
sysevent 所有事件 返回激發(fā)觸發(fā)器的事件名稱
instance_num 所有事件 返回當前數(shù)據(jù)庫的實例號
database_name 所有事件 返回當前的數(shù)據(jù)庫名字
server_error servererror 錯誤堆棧的置定位置返回錯誤號
login_user 所有事件 返回激發(fā)觸發(fā)器的用戶名
dictionary_obj_type create、alter、drop 返回激活觸發(fā)器的ddl操作的對象類型
dictionary_obj_name create、alter、drop 返回激活觸發(fā)器的ddl操作的對象名字

2.5 用戶和系統(tǒng)事件觸發(fā)器

所謂系統(tǒng)事件觸發(fā)器,就是基于Oracle系統(tǒng)事件而建立的觸發(fā)器。

該類型的觸發(fā)器可以審計數(shù)據(jù)庫的登錄、注銷以及關(guān)閉和啟動等。

??:該示例將記錄每個登錄用戶的時間,并把登錄時間存放到用戶登錄記錄表中。

具體步驟如下:

1)創(chuàng)建用戶登錄日志表

CREATE TABLE LOG_USER (
    LOGONID VARCHAR2(50),
    LOGONNAME VARCHAR2(50),
    LOGONTIME DATE, 
  CONSTRAINT LOG_USER_PRK PRIMARY KEY(LOGONID)
);

2)創(chuàng)建觸發(fā)器。該觸發(fā)器是數(shù)據(jù)庫級,記錄每個用戶的登錄時間。具體腳本如下:

CREATE TRIGGER LOGOH_TGR
    AFTER LOGON
    ON DATABASE
BEGIN
    INSERT IOTO LOG_USER
    VALUES(LOG_TAB_ID.NEXTVXL,SYS.LOGIN_PSBR,SYSDATB); 
END;
/

2.6 設(shè)置觸發(fā)器是否可用

觸發(fā)器被創(chuàng)建后,會不斷地被激發(fā),如果業(yè)務(wù)上不需要使用該觸發(fā)器了,則可以設(shè)置其是 否可用屬性,而不必把它刪除。
利用 ENABLE | DISABLE關(guān)鍵詞設(shè)置該觸發(fā)器是否可用。設(shè)置語法如下:

ALTBR TRIGGER [schena.]trigger DISABLE | ENABLE;

??:設(shè)置DDL_TGR觸發(fā)器不可用

alter trigger DDL_TGR disable;

2.7 查看觸發(fā)器狀態(tài)

select trigger_name,trigger_type,status from user_triggers;

其中 status為ENABLED表示當前觸發(fā)器啟用狀態(tài)。DISABLED表示當前觸發(fā)器禁用狀態(tài)。

3. 修改觸發(fā)器

修改觸發(fā)器同樣使用 replace 關(guān)鍵字。

在創(chuàng)建觸發(fā)器時帶上or replace關(guān)鍵字,從而完成觸發(fā)器的修改,也就是覆蓋。

4. 刪除觸發(fā)器

語法:

drop trigger [schema.]trigger_name;

??:刪除觸發(fā)器 DDL_TGR

drop trigger DDL_TGR;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 觸發(fā)器是許多關(guān)系數(shù)據(jù)庫系統(tǒng)都提供的一項技術(shù)。在 ORACLE 系統(tǒng)里,觸發(fā)器類似過程和函數(shù),都有聲明,執(zhí)行和異常處...
    遼A丶孫悟空閱讀 1,276評論 0 14
  • 觸發(fā)器分類 SQL Server提供三類觸發(fā)器: DML觸發(fā)器:在數(shù)據(jù)庫中發(fā)生數(shù)據(jù)操作(Insert、Update...
    不知名的蛋撻閱讀 1,806評論 0 5
  • 觸發(fā)器和存儲過程比較相似,都是由PL/SQL編寫并存儲在數(shù)據(jù)庫中的完成某種功能的程序,不同的是存儲過程由用戶、應(yīng)用...
    滴滴滴9527閱讀 1,430評論 0 0
  • 概述 觸發(fā)器是一種特殊類型的存儲過程。觸發(fā)器重要是通過事件進行觸發(fā)而被執(zhí)行的,而存儲過程可以通過存儲過程名被直接調(diào)...
    若能遇見閱讀 573評論 0 0

友情鏈接更多精彩內(nèi)容