一、DML触发器
触发器的作用即当某个事件发生时会自动执行执行程序段里的内容。
触发器可以作用于表或者视图,可以指定在insert 或update 或delete 操作前、操作时、操作后 执行特定的程序段。
CREATE [OR REPLACE] TRIGGER triggername
BEFORE/INSTEAD OF/AFTER ---选择事件触发(前,时,后)执行 PL/SQL代码块
[INSERT [OR] UPDATE [OR] DELETE] ---当执行 插入 、更新、删除前触发
ON tblname_or_viewname ---确认作用的表或者视图
[Referencing {OLD [AS] old / NEW [AS] new }]
[FOR EACH ROW] --指定行级触发器,不指定就是表级触发器
[WHEN (condition)] --当符合condition的条件满足时触发
DECLARE
-- local variables here
BEGIN
;--PL/SQL block
END triggername ;
在sqlserver 中 Deleted 是一张临时表存即将被更新删除的老信息,对应Oracle 中的 :old ,Inserted 是一张临时表用来存即将插入更新的新信息,对应Oracle 中的 :new。 :new 和:old 表示即将操作的一行数据而不是代表整个数据集,所以,在用这两个的时候通常要加上[FOR EACH ROW] 来指明行触发器。 其中 对于update的操作实际上是先把数据放入:old再删除再把新数据放入:new插入到数据库中。
由于:old是存的是老数据是即将被删除或更改的,所以更新old没意义。after 已经完成的操作后再触发,所以此时对新数据new进行操作是无意义的。当为after时,无法修改 :new的记录。
对于多表视图,是可以改变键保留表中的内容的。也可以对单表视图j进行DML操作
表级触发器在当对表或视图事件触发时,只执行1次。而行级触发器在对表或视图事件触发时,每影响1行数据就会执行1次程序块内容
在DML触发器中 不能使用rollback ,commit 还有DDL语句。
新建练习表 department_tbl:
新建如下触发器,比较效果
create view VW_department_tbl as select * from department_tbl;
--------insert视图VW_department_tbl时,给每行数据Leaders 默认值'BOSS'----
create or replace trigger departInsertDefault2
Instead of insert --替换原有的insert语句,且Instead Of 只能作用于视图, WHEN不能用于 INSTEAD OF
on VW_department_tbl
FOR EACH ROW
declare
begin
if :new.leaders is null then
insert into department_tbl values(:new.department,:new.all_salary,'BOSS');
else
insert into department_tbl values(:new.department,:new.all_salary,:new.leaders);
end if;
end departInsertDefault2 ;
drop trigger departInsertDefault2;
-----------------------------------
--------insert表department_tbl时,给每行数据Leaders 默认值'BOSS'----
create or replace trigger departInsertDefault1
before insert
on department_tbl
FOR EACH ROW
WHEN (new.leaders is null
)declare
begin
:new.leaders :='BOSS';
end departInsertDefault1 ;
drop trigger departInsertDefault1;
对触发器2执行
对触发器1执行
新建触发器3,
create or replace procedure dep_insert(dep in department_tbl.department%type ,sal in department_tbl.all_salary%type)
is PRAGMA AUTONOMOUS_TRANSACTION; --自主事物处理
begin
insert into department_tbl values(dep,sal,'BOSS');
--update department_tbl set leaders='BOSS' where leaders is null and department = dep; --取不到还未提交的数据
commit;
end dep_insert;
/
create or replace trigger departInsertDefault3
after insert --after 无法修改基表的数据,需要自主事物处理的存储过程配合,且新数据属于未提交状态
on department_tbl
FOR EACH ROW
WHEN (new.leaders is null)
declare
v_data department_tbl%rowtype;
begin
--update department_tbl set leaders='BOSS' where leaders is null and department = :new.department; --无法执行
dep_insert( :new.department,:new.all_salary);
end departInsertDefault3 ;
drop trigger departInsertDefault3;
执行
总之,如果要修改数据建议用 before ,after适用于数据校验,而Instead of只能作用于视图。
update 示例:
create or replace trigger departInsertDefault4
before update
on department_tbl
FOR EACH ROW
when (old.department = new.department)
declare
begin
:new.all_salary := :new.all_salary+:old.all_salary;
end departInsertDefault4 ;
/
--drop trigger departInsertDefault4;
truncate table department_tbl;
insert into department_tbl(department,all_salary) values('部门1',2000);
insert into department_tbl(department,all_salary,leaders) values('部门1',2000,'BOSS');
insert into department_tbl(department,all_salary,leaders) values('部门2',3000,'雇佣者1');
update department_tbl set department = '部门999' where Leaders is not null;
update department_tbl set Leaders = 'boss' where Leaders is not null;
commit;
select * from department_tbl;
最后执行结果:
二、模式(DDL)触发器
Create table obj_tbl(
obj_name varchar2(30),
obj_type varchar2(20),
obj_date Date
)
create or replace trigger obj_trigger
after Create --alter drop
on SCHEMA
BEGIN
insert into obj_tbl values( ora_dict_obj_name,ora_dict_obj_type,SYSDATE);
END;
/
ora_client_ip_address | 用于返回客户端的IP地址 |
ora_database_name | 用于返回当前数据库名 |
ora_des_encrypted_password | 用于返回DES加密后的用户口令 |
ora_dict_obj_name | 用于返回DDL操作所对应的数据库对象名 |
ora_dict_obj_name_list(name_list_ OUT ora_name_list_t) | 用于返回字事件中被修改的对象名列表 |
ora_dict_obj_owner | 用于返回DDL操作所对应的对象的所有者名。 |
ora_dict_obj_ower_list(ower_list OUT ora_name_list_t) | 用于返回在事件中被修改对象的所有者列表 |
ora_dict_obj_type | 用于返回DDL操作所对应的数据库对象的类型。 |
ora_grantee(user_list OUT ora_name_list_t) | 用于返回授权时事件授权者。 |
ora_instance_num | 用于返回历程号。 |
ora_is_alter_column(column_name IN VARCHAR2) | 用于检测特定列是否被修改 |
ora_is_creating_nested_table | 用于检测是否正在建立嵌套表 |
ora_is_drop_column(column_name IN VARCHAR2) | 用于检测特定列是否被删除 |
ora_is_servererror(error_number) | 用于检测是否返回了特定Oracle错误。 |
ora_login_user | 用于返回登录用户名 |
ora_sysevent | 用于返回触发 触发器的系统时间名。 |
三、数据库级触发器
----数据库启动触发器-----
create or replace trigger db_trigger
after startup on database
begin
insert into obj_tbl values( ora_sysevent,null,SYSDATE);
end;
/
----数据库用户登录触发器-----
create or replace trigger user_trigger
after logon on database
begin
insert into obj_tbl values( ora_login_user,ora_client_ip_address,SYSDATE);
end;
/
四、对触发器的操作
alter tigger tiggername ENABLE/DISABLE 打开关闭触发器
select * from dba_triggers/user_triggers 查询触发器信息