oracle 觸發器

DML 觸發器: 
對錶執行Insert、Update、Delete操作時激發 
可以用於執行校驗、設置初使值、審覈改變、甚至禁止某種DML操作 
語法: 
CREATE OR REPLACE TRIGGER 觸發器名稱 
{AFTER|BEFORE } -- 指定觸發時機 
{INSERT OR DELETE OR UPDATE} -- 指定觸發器事件 
ON 表名  --指定所監控的表 
{FOR EACH ROW|FOR EACH STATEMENT} -- 指定觸發器次數 
BEGIN 
--代碼; 
END; 
  
相關概念: 
AFTER|BEFORE:在什麼事件之前或之後執行 
INSERT|DELETE|UPDATE:什麼事件 
ON 表名:觸發器建在什麼表上,即監控什麼表 
FOR EACH ROW:行級觸發,示例:delete from t1,刪除1000行,則執行1000次(一行一次) 
FOR EACH STATEMENT:語句級觸發,示例: delete from t1,刪除1000行,則執行1次(一句一次) 
:new 行變量:保存事件發生時新數據所在行,只有insert事件和update事件纔有新數據 
:old 行變量:保存事件發生時舊數據所在行,只有delete事件和update事件纔有舊數據 
  
示例:指出事件,及事件中的新數據和舊數據 
insert into emp(empno,ename) values(51,'job'); 
分析:只有一行新數據(51,job),對應:new變量。 

update emp set ename='oracle' where empno = 51; 
分析:舊數據 (51,job)   ,對應:old變量。 
新數據(51,oracle),對應:new變量。 

delete from emp where empno = 51; 
分析:只有一行舊數據(51,oracle),對應:old變量。 
Sql代碼 
-- 顯示觸發器   
select trigger_name,status from user_triggers;   
-- 禁止觸發器   
alter trigger tr_emp_salary disable;   
-- 激活觸發器   
alter trigger tr_emp_salary enable;   
-- 禁止表的所有觸發器   
alter table employee disable all triggers;   
-- 激活表的所有觸發器   
alter table employee enable all triggers;   
-- 重新編譯觸發器   
--alter table tr_emp_salary compile;   
-- 刪除觸發器   
drop trigger tr_emp_salary;  

-- 顯示觸發器
select trigger_name,status from user_triggers;
-- 禁止觸發器
alter trigger tr_emp_salary disable;
-- 激活觸發器
alter trigger tr_emp_salary enable;
-- 禁止表的所有觸發器
alter table employee disable all triggers;
-- 激活表的所有觸發器
alter table employee enable all triggers;
-- 重新編譯觸發器
--alter table tr_emp_salary compile;
-- 刪除觸發器
drop trigger tr_emp_salary;

Sql代碼 
-- 語句級觸發器   
-- 禁止員工在休息日改變僱員信息   
create or replace trigger tr_sec_emp   
  -- before:在DML事件之前執行   
  before insert or update or delete  
  on employee   
  -- 如果在這裏沒有指定是行級還是語句級觸發器,默認就是 FOR EACH STATEMENT   
begin  
  if to_char(sysdate,'DAY','nls_date_language=AMERICAN')   
     in('SAT','SUN') then  
        case  
           -- 當觸發事件是Insert操作時,該條件謂詞返回值爲True,否則爲False   
           when inserting then  
              raise_application_error(-20001,'不能在休息日增加僱員信息!');   
           -- 當觸發事件是Update操作時,該條件謂詞返回值爲True,否則爲False   
           when updating then  
              raise_application_error(-20002,'不能在休息日修改僱員信息!');   
           -- 當觸發事件是Delete操作時,該條件謂詞返回值爲True,否則爲False   
           when deleting then  
              raise_application_error(-20003,'不能在休息日刪除僱員信息!');   
        end case;   
  end if;      
end;   
/  

-- 語句級觸發器
-- 禁止員工在休息日改變僱員信息
create or replace trigger tr_sec_emp
  -- before:在DML事件之前執行
  before insert or update or delete
  on employee
  -- 如果在這裏沒有指定是行級還是語句級觸發器,默認就是 FOR EACH STATEMENT
begin
  if to_char(sysdate,'DAY','nls_date_language=AMERICAN')
     in('SAT','SUN') then
        case
           -- 當觸發事件是Insert操作時,該條件謂詞返回值爲True,否則爲False
           when inserting then
              raise_application_error(-20001,'不能在休息日增加僱員信息!');
           -- 當觸發事件是Update操作時,該條件謂詞返回值爲True,否則爲False
           when updating then
              raise_application_error(-20002,'不能在休息日修改僱員信息!');
           -- 當觸發事件是Delete操作時,該條件謂詞返回值爲True,否則爲False
           when deleting then
              raise_application_error(-20003,'不能在休息日刪除僱員信息!');
        end case;
  end if;   
end;
/

Sql代碼 
-- 限制員工的工資不能超過當前的最高工資   
create or replace trigger tr_emp_salary before   
  -- update of 後面指定在那些列被改變時才調用這個觸器,如果不加of 默認是所有列   
  update of salary on employee   
  -- 指定該觸發器爲行級觸發器   
  for each row   
-- 如果要定義變量,則只能在Declare中定義   
declare  
  maxSalary number(10,2);   
begin  
  select max(salary) into maxSalary from employee;   
  if :new.salary > maxSalary then  
     raise_application_error(-20010,'員工工資超出工資上限!');   
  end if;   
end;   
/  

-- 限制員工的工資不能超過當前的最高工資
create or replace trigger tr_emp_salary before
  -- update of 後面指定在那些列被改變時才調用這個觸器,如果不加of 默認是所有列
  update of salary on employee
  -- 指定該觸發器爲行級觸發器
  for each row
-- 如果要定義變量,則只能在Declare中定義
declare
  maxSalary number(10,2);
begin
  select max(salary) into maxSalary from employee;
  if :new.salary > maxSalary then
     raise_application_error(-20010,'員工工資超出工資上限!');
  end if;
end;
/

Sql代碼 
-- 設置員工的工資不能低於原工資,但也不能高出原工資的20%   
create or replace trigger tr_emp_say before update of salary   
  on employee for each row   
  -- 設置執行觸發器的條件   
  when (new.salary < old.salary or new.salary > old.salary*1.2)   
  begin  
    raise_application_error(-20011,'員工的不能降薪,但工資升幅不能超過20%!');    
end;   

-- 設置員工的工資不能低於原工資,但也不能高出原工資的20%
create or replace trigger tr_emp_say before update of salary
  on employee for each row
  -- 設置執行觸發器的條件
  when (new.salary < old.salary or new.salary > old.salary*1.2)
  begin
    raise_application_error(-20011,'員工的不能降薪,但工資升幅不能超過20%!'); 
end; 

在CMD中執行:audit insert,update,delete on employee by access; 
可以設置Employee表的審計選項,如果在Employee表上執行了Insert、 
Update和Delete操作,Oracle會將關於SQL操作的信息(用戶、時間等) 
寫入數據字典中,但使用數據庫審計只能審計SQL操作,而不能記載數據變化 

Instead of 觸發器: 
它是DML觸發器的替代品,控制對視圖的操作,它可以使不能更新的視圖變爲可更新, 
以及覆蓋可更新的視圖的行爲  
注意: 
Instead of 選項只適用於視圖 
當基於視圖建立觸發器時,不能指定Before和After選項 
在建立視圖時沒有指定with check option選項 
當建立Instead of觸發器時,必須指定for each row選項 
Sql代碼 
-- 創建用戶表   
-- drop table users;   
create table users(   
       userId int not null,   
       username varchar(20) not null,   
       password varchar2(50) not null,   
       logintime date not null  
)   
-- 向用戶表中插入數據   
insert into users values(1,'user1',11111,sysdate);   
insert into users values(2,'user2',22222,sysdate);   
insert into users values(3,'user3',33333,sysdate);   
insert into users values(4,'user4',44444,sysdate);   
insert into users values(5,'user5',55555,sysdate);   
select * from users;   
-- 建立複雜視圖   
-- drop view emp_users;   
create or replace view emp_users as  
select distinct e.empno,e.name,u.username from employee e,users u where e.empno = u.userId;   
  
select * from emp_users;   
-- drop view tr_instead_of_emp_users;   
create or replace trigger tr_instead_of_emp_users   
instead of insert on emp_users for each row   
declare  
   i_temp int;   
begin  
   -- 同時向兩張表中插入數據   
   select count(*) into i_temp from employee where empno = :new.empno;   
   if i_temp = 0 then  
      insert into Employee values(:new.empno,:new.name,'銷售經理',1,'2009-01-09',5300,'銷售',4);   
   end if;   
      
   select count(*) into i_temp from users where userId = :new.empno;   
   if  i_temp = 0 then  
      insert into users values(:new.empno,:new.username,55555,sysdate);   
   end if;   
end;   
/  

-- 創建用戶表
-- drop table users;
create table users(
       userId int not null,
       username varchar(20) not null,
       password varchar2(50) not null,
       logintime date not null
)
-- 向用戶表中插入數據
insert into users values(1,'user1',11111,sysdate);
insert into users values(2,'user2',22222,sysdate);
insert into users values(3,'user3',33333,sysdate);
insert into users values(4,'user4',44444,sysdate);
insert into users values(5,'user5',55555,sysdate);
select * from users;
-- 建立複雜視圖
-- drop view emp_users;
create or replace view emp_users as
select distinct e.empno,e.name,u.username from employee e,users u where e.empno = u.userId;

select * from emp_users;
-- drop view tr_instead_of_emp_users;
create or replace trigger tr_instead_of_emp_users
instead of insert on emp_users for each row
declare
   i_temp int;
begin
   -- 同時向兩張表中插入數據
   select count(*) into i_temp from employee where empno = :new.empno;
   if i_temp = 0 then
      insert into Employee values(:new.empno,:new.name,'銷售經理',1,'2009-01-09',5300,'銷售',4);
   end if;
   
   select count(*) into i_temp from users where userId = :new.empno;
   if  i_temp = 0 then
      insert into users values(:new.empno,:new.username,55555,sysdate);
   end if;
end;
/

Sql代碼 
-- 測試Instead of 觸發器   
insert into emp_users values(10,'王五','小李');   
insert into emp_users values(11,'張三','小明');   
select * from emp_users;  

-- 測試Instead of 觸發器
insert into emp_users values(10,'王五','小李');
insert into emp_users values(11,'張三','小明');
select * from emp_users;

數據庫事件觸發器: 
在數據庫啓動、關閉、用戶登錄、退出或者Oracle錯誤發生時,以及執行創建、刪除表、索引等DDL語句時激發 
主要用於跟蹤數據庫活動 
創建打開數據庫觸發器:after startup 
創建用戶登錄觸發器:after logon 
創建用戶退出觸發器:before logoff 
創建DDL觸發器:after ddl 
Sql代碼 
-- 建立用戶登錄的觸發器   
create or replace trigger tr_logon after logon on database  
   begin  
   raise_application_error(-20001,ora_login_user || '用戶登錄數據庫!');   
end;   
/   
-- 建立用戶退出的觸發器   
create or replace trigger tr_logoff before logoff on database  
   begin  
   raise_application_error(-20002,ora_login_user || '用戶退出數據庫!');   
end;   
/   

-- 創建DDL日誌表   
create table ddl_log   
(   
  -- DDL事件   
  ddl_event varchar2(20),   
  -- 對應的數據庫登錄用戶名   
  username varchar2(10),   
  -- 對應的對象的所有者名   
  owner varchar2(10),   
  -- 對應的數據庫對象名   
  objname varchar2(50),   
  -- 對應的數據庫對象類型   
  objtype varchar2(10),   
  -- 對應的數據庫操作時間   
  time date  
)   
-- 創建DDL觸發器   
create or replace trigger tr_ddl_log   
after ddl on database  
begin  
      insert into ddl_log values(   
      ora_sysevent,ora_login_user,ora_dict_obj_owner,   
      ora_dict_obj_name,ora_dict_obj_type,sysdate   
      );   
end;   
  
select * from ddl_log   
-- 測試DDL觸發器   
create table aa(aid int)   
drop table aa  

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