日期:2014-05-17  浏览次数:21017 次

如何根据明细表的状态变化,实时修改主表的状态
以采购单为例:

两个业务表,一个明细表D,一个主表M
明细表有4个状态:0-取消,1-新单,2-生效,99-结案
当明细表所有项为99-结案时,更新主表的状态为99-结案,表示此采购单已完结。

原计划在明细表增加Trigger,,当明细表项的状态转为99时,触发检查整张采购单的项次是否全部为99-结案,如果所有项次全部为99-结案,则更新主表采购单的状态为99-结案。

***由于Trigger访问表本身,抛出ORA-04091异常

查阅了很多文章,用包变量或用视图触发器,都没能实现上面很简单的业务功能..

请问:
1.如果用触发器,要怎么解决:Trigger访问表本身,ORA-04091异常
2.除了触发器,还能用什么方法实现以上业务功能?

請幫忙看看咯。。


------解决方案--------------------
帮顶.
如果不行就重新设计表吧.增加一个中间表.
------解决方案--------------------
SQL code
--应该不难的,给你个例子参考一下或者你把表结构和数据贴出来。
SQL> DESC EMP_TEST;
Name     Type         Nullable Default Comments 
-------- ------------ -------- ------- -------- 
EMPNO    NUMBER(4)    Y                         
ENAME    VARCHAR2(10) Y                         
JOB      VARCHAR2(9)  Y                         
MGR      NUMBER(4)    Y                         
HIREDATE DATE         Y                         
SAL      NUMBER(7,2)  Y                         
COMM     NUMBER(7,2)  Y                         
DEPTNO   NUMBER(2)    Y                         

SQL> SELECT * FROM EMP_TEST;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7369 SMITH      CLERK      7902 1980-12-17     800.00               20

Executed in 0.016 seconds

-- package 代码:
CREATE OR REPLACE PACKAGE SCOTT.PKG_TRIGGER_TEST  IS
  TYPE T_EMP IS TABLE OF SCOTT.EMP_TEST%ROWTYPE INDEX BY BINARY_INTEGER;
  V_EMPS T_EMP;
  V_NUM BINARY_INTEGER := 0;
END ;

-- 行级触发器得发NEW值:
CREATE OR REPLACE TRIGGER SCOTT.GET_EMP_ROW
  AFTER INSERT ON SCOTT.EMP_TEST  
  FOR EACH ROW
BEGIN
  DBMS_OUTPUT.PUT_LINE('-- TRIGGER SCOTT.GET_EMP_ROW START --');
  SCOTT.PKG_TRIGGER_TEST.V_NUM := SCOTT.PKG_TRIGGER_TEST.V_NUM + 1;
  SCOTT.PKG_TRIGGER_TEST.V_EMPS(SCOTT.PKG_TRIGGER_TEST.V_NUM).EMPNO := :NEW.EMPNO;
  SCOTT.PKG_TRIGGER_TEST.V_EMPS(SCOTT.PKG_TRIGGER_TEST.V_NUM).ENAME := :NEW.ENAME;
  SCOTT.PKG_TRIGGER_TEST.V_EMPS(SCOTT.PKG_TRIGGER_TEST.V_NUM).JOB := :NEW.JOB;
  SCOTT.PKG_TRIGGER_TEST.V_EMPS(SCOTT.PKG_TRIGGER_TEST.V_NUM).MGR := :NEW.MGR;
  SCOTT.PKG_TRIGGER_TEST.V_EMPS(SCOTT.PKG_TRIGGER_TEST.V_NUM).HIREDATE := :NEW.HIREDATE;
  SCOTT.PKG_TRIGGER_TEST.V_EMPS(SCOTT.PKG_TRIGGER_TEST.V_NUM).SAL := :NEW.SAL;
  SCOTT.PKG_TRIGGER_TEST.V_EMPS(SCOTT.PKG_TRIGGER_TEST.V_NUM).COMM := :NEW.COMM;
  SCOTT.PKG_TRIGGER_TEST.V_EMPS(SCOTT.PKG_TRIGGER_TEST.V_NUM).DEPTNO := :NEW.DEPTNO;
  
EXCEPTION
  WHEN OTHERS THEN
       DBMS_OUTPUT.PUT_LINE(SQLCODE||' : '||SQLERRM);
  
END GET_EMP_ROW;

-- 表级触发器得到最大工资等Operation:
CREATE OR REPLACE TRIGGER SCOTT.TIA_T_RESULT_HEAD
  AFTER INSERT ON SCOTT.EMP_TEST
DECLARE
  -- local variables here
  V_EMP_NO NUMBER;
  V_MANAGER_NO NUMBER;
  V_EMP_DATE DATE;
  V_DEPT_NO NUMBER;
  
  V_MAX_SALARY SCOTT.EMP_TEST.SAL%TYPE;
  
  V_STEP VARCHAR2(100) := '';
BEGIN
  DBMS_OUTPUT.PUT_LINE('-- TRIGGER SCOTT.TIA_T_RESULT_HEAD START --');
  V_STEP := 'GET NEW VALUES';
  FOR I IN 1..SCOTT.PKG_TRIGGER_TEST.V_EMPS.COUNT LOOP
      V_EMP_NO     := SCOTT.PKG_TRIGGER_TEST.V_EMPS(I).EMPNO;
      V_MANAGER_NO := SCOTT.PKG_TRIGGER_TEST.V_EMPS(I).MGR;
      V_EMP_DATE   := SCOTT.PKG_TRIGGER_TEST.V_EMPS(I).HIREDATE;
      V_DEPT_NO    := SCOTT.PKG_TRIGGER_TEST.V_EMPS(I).DEPTNO;
      
      DBMS_OUTPUT.PUT_LINE('EMP_NO: '||V_EMP_NO||' MANAGER_NO: '||V_MANAGER_NO||' EMP_DATE: '||V_EMP_DATE||' DEPT_NO: '||V_DEPT_NO);
      
      V_STEP := 'GET MAX SALARY';
      SELECT NVL(MAX(SAL),0) 
        INTO V_MAX_SALARY 
        FROM SCOTT.EMP_TEST
       WHERE DEPTNO = V_DEPT_NO;
      
      V_STEP := 'PRINT MAX SALARY AFTER INSERTED RECORDS';
      DBMS_OUTPUT.PUT_LINE('MAX SALARY: '||V_MAX_SALARY);
      DBMS_OUTPUT.PUT_LINE('');
      
  END LOOP;
  
EXCEPTION
  WHEN OTHERS THEN
       DBMS_OUTPUT.PUT_LINE('Error at : '||V_STEP);
       DBMS_OUTPUT.PUT_LINE(SQLCODE||'