`

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;

 

 Links

问题

我要对表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://stackoverflow.com/questions/786733/oracle-pl-sql-loop-over-trigger-columns-dynamically老外也有这样的疑问

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics