Oracle触发器
近日需要用到Oracle触发器,从网上看了些资料,做下摘记。
理论知识
触发器的概念和类型
触发器是一种特殊的存储过程,它在插入,删除或修改特定表中的数据时触发执行,它比数据库本身标准的功能有更精细和更复杂的数据控制能力。数据库触发器有以下的作用:
- 安全性。可以基于数据库的值使用户具有操作数据库的某种权利。
# 可以基于时间限制用户的操作,例如不允许下班后和节假日修改数据库数据。
# 可以基于数据库中的数据限制用户的操作,例如不允许股票的价格的升幅一次超过10%。
- 审计。可以跟踪用户对数据库的操作。
# 审计用户操作数据库的语句。
# 把用户对数据库的更新写入审计表。
- 实现复杂的数据完整性规则。
# 实现非标准的数据完整性检查和约束。触发器可产生比规则更为复杂的限制。与规则不同,触发器可以引用列或数据库对象。例如,触发器可回退任何企图吃进超过自己保证金的期货。
# 提供可变的缺省值。
- 实现复杂的非标准的数据库相关完整性规则。触发器可以对数据库中相关的表进行连环更新。例如,在auths表author_code列上的删除触发器可导致相应删除在其它表中的与之匹配的行。
# 在修改或删除时级联修改或删除其它表中的与之匹配的行。
# 在修改或删除时把其它表中的与之匹配的行设成NULL值。
# 在修改或删除时把其它表中的与之匹配的行级联设成缺省值。
# 触发器能够拒绝或回退那些破坏相关完整性的变化,取消试图进行数据更新的事务。当插入一个与其主健不匹配的外部键时,这种触发器会起作用。例如,可以在books.author_code列上生成一个插入触发器,如果新值与auths.author_code列中的某值不匹配时,插入被回退。
- 同步实时地复制表中的数据。
* 自动计算数据值,如果数据的值达到了一定的要求,则进行特定的处理。例如,如果公司的帐号上的资金低于5万元则立即给财务人员发送警告数据。
示例代码
【案例一】
--触发器: --添加员工信息,流水号作为自动编号(通过序列生成), --并且判断如果工资小于0,则改为0;如果大于10000,则改为10000。 CREATE TABLE emp2( e_id NUMBER, e_no NUMBER, e_name VARCHAR2(20), e_sal NUMBER ) SELECT * FROM emp2; CREATE SEQUENCE seq_trg_id; INSERT INTO emp2(e_id,e_no,e_name,e_sal) VALUES(seq_trg_id.nextval,7788,'章子', 1000000000000) INSERT INTO emp2(e_id,e_no,e_name,e_sal) VALUES(seq_trg_id.nextval,7788,'章子怡',-10) CREATE OR REPLACE TRIGGER trg_add_emp_info BEFORE INSERT ON emp2 FOR EACH ROW DECLARE -- local variables here BEGIN SELECT seq_trg_id.NEXTVAL INTO :NEW.e_id FROM dual; IF :NEW.e_sal < 0 THEN :NEW.e_sal := 0; ELSIF :NEW.e_sal > 10000 THEN :NEW.e_sal := 10000; END IF; END;
【案例二】
--扩充练习: --为emp建立触发器,将删除的记录放到emp3表中(autoid,deptno,empno,ename,del_rq-删除日期) --测试代码 CREATE TABLE emp3( autoid NUMBER PRIMARY KEY, deptno NUMBER, empno NUMBER, ename VARCHAR2(20), del_rq DATE ) CREATE SEQUENCE seq_trg_del_autoid; INSERT INTO emp (empno, ename, deptno) VALUES (114, '阿娇', 10); COMMIT; SELECT * FROM emp; DELETE emp WHERE empno = 114; SELECT * FROM emp3; --答案: CREATE OR REPLACE TRIGGER trg_del_emp_info BEFORE DELETE ON emp FOR EACH ROW DECLARE -- local variables here BEGIN INSERT INTO emp3(autoid,deptno,empno,ename,del_rq) VALUES(seq_trg_del_autoid.NEXTVAL,:OLD.deptno,:OLD.empno,:OLD.ename,sysdate); END;
- http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96590/adg13trg.htm
- http://blog.chinaunix.net/u1/59114/showart_469405.html
- http://blog.csdn.net/justdo2008/archive/2009/04/29/4137779.aspx
问题
我要对表T的删除数据做备份,于是复制一张T_BAK和表T一样的表另加上操作时间字段。建立表T的删除触发器。其实就是在触发器中把删除的记录插入到T_BAK中。但是如果T_BAK的字段非常多,而且写类似的触发器也很多,要是一个一个字段敲,那不是即费事又容易出错。于是想有没有办法可以一次获取:NEW或:OLD的变量的所有列的值呢?查找了半天也没有答案,看似ORACLE没有实现这个功能?
代码类似这样:
create or replace trigger Trig_on_test before delete on test referencing old as o --为了练习声明别名 for each row declare PK_conflict Exception; --自定义异常,用于练习 iCount int:=0; begin select count(*) into iCount from test1 where id=:o.id; if iCount>0 then raise PK_conflict; end if; --触发器中不能操作触发自己的表 --insert into test1(id,name,op_time) select t.*, sysdate from test t where t.id=:o.id; insert into test1 values(:o.id,:o.name,sysdate); --如果TEST1表中字段N多,难道就只能一个个写?考虑过动态SQL,但前题是要取到:Old变量的所有值,如何取?是否支持? Exception when PK_conflict then DBMS_output.put_line('表中已经有这条记录了'); end;
http://*.com/questions/786733/oracle-pl-sql-loop-over-trigger-columns-dynamically老外也有这样的疑问
上一篇: Oracle触发器
下一篇: XPath 简单语法