欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Oracle触发器

程序员文章站 2022-07-14 13:01:27
...

 

近日需要用到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://*.com/questions/786733/oracle-pl-sql-loop-over-trigger-columns-dynamically老外也有这样的疑问

 

上一篇: Oracle触发器

下一篇: XPath 简单语法