Oracle觸發器學習與實踐

一、觸發器簡介

       觸發器可以看作一種“特殊”的存儲過程,它定義了一些與數據庫相關事件(如:INSERT、UPDATE、CREATE等事件)發生時應執行的“功能代碼塊”,通常用於管理複雜的完整性約束,或監控對錶的修改,或通知其他程序,甚至可以實現對數據的審計功能。
      在觸發器中有一個觸發事件,觸發器是通過這個“觸發事件”來執行的(而存儲過程的調用或執行是由用戶或應用程序進行的)。能夠引起觸發器運行的操作被稱爲“觸發事件”,如執行DML語句(使用INSERT、UPDATE、DELETE語句對錶或視圖執行數據處理操作);執行DDL語句(CREATE、ALTER、DROP語句在數據庫中創建、修改、刪除模式對象);引發數據庫系統事件(如系統啓動或退出、產生異常錯誤等);引發用戶事件(如登錄或退出數據庫操作)。
       因此觸發器不能接收參數,不需要人爲的去調用,也不能調用。其觸發器的觸發條件其實在你定義的時候就已經設定好了。

二、觸發器語法

    語法格式如下:

create [or replace] tigger tri_name
     [before | after | instead of] tri_event
     on table_name | view_name | user_name | db_name
     [for each row] [when tri_condition]
begin
     plsql_sentences;
end tri_name;

關鍵字:
     trigger:表示創建觸發器的關鍵字,就如同創建存儲過程的關鍵字“produce”一樣。
     before | after | instead of:表示“出發時機”的關鍵字。before表示在執行DML等操作之前觸發,這種方式能夠防止某些錯誤操作發生而便於回滾或是實現某些業務規則;after表示在DML等操作發生之後發生,這種方式便於記錄該操作或做某些事後處理信息;instead of表示觸發器爲替代觸發器。
      on:表示操作的數據表、視圖、用戶模式和數據庫等,對它們執行某種數據操作(比如對錶執行INSERT、ALTER、DROP等操作),將引起觸發器的運行。
      for each row:指定觸發器爲行級觸發器,當DML語句對每一行數據進行操作時都會引起該觸發器的運行。如果未指定該條件,則表示創建語句級觸發器,這時無論數據操作影響多少行,觸發器都只會執行一次。
語法中的參數及說明:
      tri_name:觸發器的名稱,如果數據庫中已經存在了此名稱,則可以指定“or replace”關鍵字,這樣新的觸發器將覆蓋掉原來的觸發器。
      tri_event:觸發事件,比如常用的INSERT、UPDATE [OF 列名]、DELETE、CREATE、ALTER、DROP等。
      table_name | view_name | user_name |db_name:分別表示操作的數據表、視圖、用戶模式和數據庫,對它們的某些操作將引起觸發器的運行。
      tri_condition:表示觸發器條件表達式,只有當該表達式的值爲true時,遇到觸發事件纔會自動執行觸發器,使其執行觸發操作,否則即便是遇到觸發事件也不會執行觸發器。
      plsql_sentences:PL/SQL語句,它是觸發器功能實現的主體。

相關解釋:
       DML(data manipulation language)數據操縱語言:就是我們最經常用到的 SELECT、UPDATE、INSERT、DELETE。 主要用來對數據庫的數據進行一些操作。
       DDL(data definition language)數據庫定義語言:其實就是我們在創建表的時候用到的一些sql,比如說:CREATE、ALTER、DROP等。DDL主要是用在定義或改變表的結構,數據類型,表之間的鏈接和約束等初始化工作上。

三、觸發器種類

      行級觸發器:當DML語句對每一行數據進行操作時都會引起該觸發器的運行。
      語句級觸發器:無論DML語句影響多少行數據,其所引起的觸發器僅執行一次。
      替換觸發器:該觸發器是定義在視圖上的,而不是定義在表上,它是用來替換所使用實際語句的觸發器。它是Oracle專門爲進行視圖操作的一種處理方法。
      用戶事件觸發器:是指與DDL操作或用戶登錄、退出數據庫等事件相關的觸發器。如,用戶登錄到數據庫或使用ALTER語句修改表結構等。
      系統事件觸發器:是指在Oracle數據庫系統的事件中進行觸發的觸發器,如Oracle實例的啓動與關閉。

1)行級觸發器:
       行級觸發器會針對DML操作所影響的每一行數據都執行一次觸發器。創建這種觸發器時,必須在語法中使用for each row。使用行級觸發器的一個典型應用就是給數據表生成遞增序號。

--創建dept表,並在其中定義兩個字段,分別用來存儲id和部門名稱
create table dept(id number,name varchar2(10));

--爲了給dept表的id列生成不能重複的有序值,需要創建一個序列
create sequence seq_id;

--在創建了數據表dept和序列seq_id之後,準備工作完成,接着來創建一個觸發器,用於爲dept表的id列賦值。
--創建一個行級觸發器,該觸發器在數據表dept插入數據時被觸發,並且在該觸發器的主體中實現設置dept表的id列的值
create or replace trigger tri_insert
  before insert on dept
  for each row --對錶的每一行觸發器執行一次
begin
  select seq_id.nextval into :new.id from dual; --:NEW表示新插入的那條記錄
end;

--在觸發器創建完畢後,用戶可以通過向dept表中插入數據來驗證觸發器是否被執行,同時也能夠驗證該行級觸發器是否能夠使用序列爲表的id賦值
--例如:向goods表中插入兩條記錄,其中一條記錄不指定id列的值,由序列seq_id來產生;另一條記錄指定id的值;
insert into dept(name) values('S');
insert into dept(id,name) values(1,'S');

2)語句級觸發器:
      語句級觸發器,是針對一條DML語句而引起的觸發器執行。在語句級觸發器中,不使用for each row子句,也就是說無論數據操作影響多少行,觸發器都只會執行一次。
      下面實例要實現的主要功能是使用觸發器針對表dept表的各種操作進行監控,爲此首先需要創建一個日誌表dept_log它用於存儲對dept表的各種數據操作信息,比如操作種類(如插入、修改、刪除操作)、操作時間等。

--創建dept_log數據表,並在其中定義兩個字段,分別用來存儲操作種類信息和操作日期
create table dept_log(operate_tag varchar2(10),operate_time date);

--創建一個觸發器tri_dept,該觸發器在insert、update和delete事件下都可以被觸發,並且操作的數據對象是dept表,
--要求在觸發器執行時輸出對dept表所做的具體操作
create or replace trigger tri_dept
  before insert or update or delete on dept
declare
  var_tag varchar2(10);
begin
  if inserting then
    var_tag := '插入';
  elsif updating then
    var_tag := '修改';
  elsif deleting then
    var_tag := '刪除';
  end if;
  insert into dept_log values (var_tag, sysdate);
end tri_dept;
 
--驗證
insert into dept values(1,'N');
update dept set name='GG';  
delete dept; 

3)替換觸發器:
      替換觸發器-instead of觸發器,它的“觸發時機”關鍵字是instead of,而不是before或after。與其他類型觸發器不同是,替換觸發器定義在視圖(一種數據庫對象),而不是定義在表上。由於視圖是由多的基表連接組成的邏輯結構,所以一般不允許用戶進行DML操作(如INSERT、UPDATE、DELETE等操作),這樣當用戶爲視圖編寫“替換觸發器”後,用戶對視圖的DML操作實際上就變成了執行觸發器中的PL/SQL語句塊,這樣就可以通過在“替換觸發器”中編寫適當的代碼對構成視圖的各個基表進行操作。
(1)爲了創建並使用替換觸發器,首先需要創建一個視圖
例如:創建一個檢索僱員信息的視圖,該視圖包括dept表(部門表)和emp表(僱員表)

--創建僱員表,deptid部門id,enname僱員名稱
create table emp(deptid number,enname varchar2(10));
--創建一個檢索僱員信息的視圖,該視圖包括dept表(部門表)和emp表(僱員表)
create or replace view view_emp_dept as select * from emp,dept where emp.deptid=dept.id;

(2)接下來編寫一個關於view_emp_dept視圖在insert事件中的觸發器
例如:創建一個關於view_emp_dept視圖的替換觸發器,在該觸發器的主體中實現向emp表和dept表中插入兩行關聯的數據。

create or replace trigger tri_insert_view
  instead of insert on view_emp_dept
  for each row 
declare
  row_dept number;
begin
  select count(*) into row_dept from dept where id = :new.id;
  if row_dept = 0 then
    --判斷部門是否存在,不存在則插入
    insert into dept (id, name) values (:new.id, :new.name);
  end if;
  insert into emp (deptid, enname) values (:new.deptid, :new.enname);
end tri_insert_view;

(3)當觸發器tri_insert_view成功創建之後,在向view_emp_dept視圖中插入數據時,Oracle就不會產生錯誤信息,而是引起觸發器“tri_insert_view”的運行,從而實現向emp表和dept表中插入兩行數據。
例如:首相向視圖view_emp_dept插入一條記錄,然後在該視圖中檢索插入的記錄行。

insert into view_emp_dept(DEPTID,ENNAME,ID,NAME) values(1,'張三',1,'H')
insert into view_emp_dept(DEPTID,ENNAME,ID,NAME) values(3,'李四',3,'W')

用戶事件觸發器:
       用戶事件觸發器是因進行DDL操作或用戶登錄、退出等操作而引起運行的觸發器,,引起該類型觸發器運行的常見用戶事件包括:CREATE、ALTER、DROP、ANALYZE、COMMENT、GRANT、REVOKE、RENAME、TRUNCATE、SUSPEND、LOGON和LOGOFF等。

--創建一個日誌信息表,該表保存的日誌信息包括數據對象、數據對象類型、操作行爲、操作用戶和操作日期等
create table ddl_oper_log
(
    db_obj_name varchar2(20),
    db_obj_type varchar2(20),
    oper_action varchar2(20),
    oper_user varchar2(20),
    ope_date date
);

--創建一個用戶觸發器,用於將當前模式下的DDL操作信息保存到上面所創建的ddl_oper_log日誌信息表中。
--關於DDL操作(這裏包括CREATE、ALTER和DROP)創建一個觸發器,然後將DDL操作的相關信息插入到ddl_oper_log日誌表中
create or replace trigger tri_ddl_oper 
   before create or alter or drop 
   on SXF.schema
begin 
  insert into ddl_oper_log values(
  ora_dict_obj_name,
  ora_dict_obj_type,
  ora_sysevent,
  ora_login_user,
  sysdate);
end;

--在創建完畢觸發器之後,爲了引起觸發器的執行,就要進行DDL操作
--例如:刪除視圖,使用select語句查看ddl_oper_log日誌表中的DDL操作信息
drop view view_emp_dept;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章