PL/SQL_触发器2(行触发器)

行触发器是指执行DML操作时,每作用一行就触发一次的触发器。审计数据变化时,可以使用行触发器。建立行触发器的语法如下:
CREATE [OR REPLACE] TRIGGER trigger_name
timing event1 [OR event2 OR event3]
ON table_name
[REFERENCING OLD AS old | NEW AS new]
FOR EACH ROW
[WHEN condition]
PL/SQL block;
1、建立BEFORE行触发器
某些情况下使用约束可能无法实现复杂的商业逻辑或企业规则,此时可以考虑使用BEFORE行触发器。下面以确保雇员工资不能低于其原有工资为例,说明建立BEFORE行触发器的方法。
CREATE OR REPLACE TRIGGER tr_emp_sal
BEFORE UPDATE OF sal
ON emp
FOR EACH ROW
BEGIN
  IF :NEW.sal < :OLD.sal THEN
    RAISE_APPLICATION_ERROR(-20000,‘工资只涨不降‘);
  END IF;
END;
测试:
UPDATE emp SET sal = 800 WHERE empno = 7788;
2、建立AFTER行触发器
为了审计DML操作,可以使用语句触发器或Oracle系统提供的审计功能;而为了审计数据变化,则应该使用AFTER行触发器。下面以审计雇员工资变化为例,说明使用AFTER行触发器的方法。在建立触发器之前,首先应建立存放审计数据的表audit_emp_change,示例如下:
CREATE TABLE audit_emp_change(
  NAME VARCHAR2(10),
  oldsal NUMBER(6,2),
  newsal NUMBER(6,2),
  etime DATE
);
AFTER行触发器示例
CREATE OR REPLACE TRIGGER tr_sal_change
AFTER UPDATE OF sal
ON emp
FOR EACH ROW
DECLARE
  v_temp INTEGER;
BEGIN
  SELECT COUNT(*) INTO v_temp FROM audit_emp_change
  WHERE NAME = :OLD.ename;
  IF v_temp = 0 THEN
    INSERT INTO audit_emp_change(NAME,oldsal,newsal,etime)
    VALUES (:OLD.ename,:OLD.sal,:NEW.sal,SYSDATE);
  ELSE
    UPDATE audit_emp_change
    SET
      oldsal = :OLD.sal,
      newsal = :NEW.sal,
      etime = SYSDATE
    WHERE NAME = :OLD.ename;
  END IF;
END;
测试:
UPDATE emp SET sal = sal * 1.1 WHERE deptno = 20;
SELECT * FROM audit_emp_change;
3、限制行触发器
当使用行触发器时,默认情况下会在每个被作用行上执行一次触发器代码。为了使得在特定条件下执行行触发器代码,就需要使用WHEN子句对触发条件加以限制。
CREATE OR REPLACE TRIGGER tr_sal_change
AFTER UPDATE OF sal
ON emp
FOR EACH ROW
WHEN (OLD.job=‘CLERK‘)
DECLARE
  v_temp INTEGER;
BEGIN
  SELECT COUNT(*) INTO v_temp FROM audit_emp_change
  WHERE NAME = :OLD.ename;
  IF v_temp = 0 THEN
    INSERT INTO audit_emp_change(NAME,oldsal,newsal,etime)
    VALUES (:OLD.ename,:OLD.sal,:NEW.sal,SYSDATE);
  ELSE
    UPDATE audit_emp_change
    SET
      oldsal = :OLD.sal,
      newsal = :NEW.sal,
      etime = SYSDATE
    WHERE NAME = :OLD.ename;
  END IF;
END;
4、DML触发器使用注意事项
当编写DML触发器时,触发器代码不能从触发器所对应的基表中读取数据。
错误示例:
CREATE OR REPLACE TRIGGER tr_emp_sal
BEFORE UPDATE OF sal
ON emp
FOR EACH ROW
DECLARE
  maxsal NUMBER(6,2);
BEGIN
  SELECT MAX(sal) INTO maxsal FROM emp;
  IF :NEW.sal > maxsal THEN
    RAISE_APPLICATION_ERROR(-20000,‘超出工资上限‘);
  END IF;
END;
正确示例:
CREATE OR REPLACE PACKAGE pkg_emp
IS
  g_maxsal INTEGER;
END pkg_emp;
/
CREATE OR REPLACE TRIGGER tr_emp_sal_row
BEFORE UPDATE OF sal
ON emp
BEGIN
  SELECT MAX(sal) INTO pkg_emp.g_maxsal FROM emp;
END;
/
--DML触发器使用注意事项
CREATE OR REPLACE TRIGGER tr_emp_sal
BEFORE UPDATE OF sal
ON emp
FOR EACH ROW
BEGIN
  IF :NEW.sal > pkg_emp.g_maxsal THEN
    RAISE_APPLICATION_ERROR(-20000,‘超出工资上限‘);
  END IF;
END;
测试:
UPDATE emp SET sal = 3700 WHERE empno = 1111;

PL/SQL_触发器2(行触发器),布布扣,bubuko.com

PL/SQL_触发器2(行触发器)

上一篇:vsftpd虚拟用户+mysql数据库管理用户,pam认证


下一篇:PL/SQL_触发器5(建立系统事件触发器)