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
oracle 觸發器
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.