Oracle复合触发器变异表

时间:2015-07-01 11:19:27

标签: oracle triggers oracle12c mutation

我正在尝试创建复合触发器以避免突变问题。 我有一个表和一个python的过程来执行事务插入。该表有n个字段。 我想要做的是当其中一个字段的值为负时,然后不执行操作,并插入表的字段的先前记录(插入之前)的值。另一个问题是其中一个字段是和id,以区分网站。

不,这是我的代码,只考虑一个字段(KWHGEN):

CREATE OR REPLACE TRIGGER "CIRCU3".D_measures_TP_test
--FOR INSERT OR UPDATE ON T_MEASURES_TP_NEW
FOR INSERT ON T_MEASURES_TP_NEW
COMPOUND TRIGGER

VAL_KWHGEN NUMBER(21,2);
VAL_autoin NUMBER (19,0);

AFTER EACH ROW IS
BEGIN
SELECT autoin, KWHGEN INTO VAL_ID_MED, VAL_KWHGEN FROM
    (SELECT * 
        FROM T_measures_TP_NEW WHERE ID_site = :NEW.ID_site
       ORDER BY TIMESTAMP DESC)
    WHERE ROWNUM = 1;

IF :NEW.KWHGEN <0
  THEN UPDATE T_MEASURES_TP_NEW SET KWHGEN = VAL_KWHGEN WHERE autoin = VAL_autoin;

END IF;
END AFTER EACH ROW;

END D_MEASURES_TP_test;

但突变错误跟随我; - )

3 个答案:

答案 0 :(得分:0)

您已在T_MEASURES_TP_NEW上创建了触发器,然后在触发器中更新了相同的表T_MEASURES_TP_NEW。这将再次调用您的触发器。 如果第一次选择触发器再次在VAL_KWHGEN中返回负值,则会发生变异错误。

答案 1 :(得分:0)

您只定义了一个AFTER EACH块,没有别的。这与创建行级触发器(即使用FOR EACH ROW

相同

必须是这样(未经测试):

CREATE OR REPLACE TRIGGER "CIRCU3".D_measures_TP_test
FOR INSERT ON T_MEASURES_TP_NEW
COMPOUND TRIGGER

VAL_KWHGEN NUMBER(21,2);
VAL_autoin NUMBER (19,0);

TYPE RowIdTableType IS TABLE OF ROWID;
TYPE KWHGENTableType IS TABLE OF T_MEASURES_TP_NEW.KWHGEN%TYPE;

RowIdTable RowIdTableType;
KWHGENTable KWHGENTableType;

BEFORE STATEMENT IS   
    BEGIN       
        RowIdTable := RowIdTable();
        KWHGENTable := KWHGENTableType();
    END BEFORE STATEMENT;

BEFORE EACH ROW IS   
    BEGIN       
        RowIdTable.EXTEND;
        RowIdTable(RowIdTable.LAST) := :NEW.ROWID;
        KWHGENTable.EXTEND;
        KWHGENTable(RowIdTable.LAST) := :NEW.KWHGEN;
    END BEFORE EACH ROW;

AFTER STATEMENT IS 
    BEGIN
       FOR i IN RowIdTable.FIRST..RowIdTable.LAST LOOP
           SELECT 
                DISTINCT MIN(autoin) OVER (ORDER BY TIMESTAMP DESC), 
                DISTINCT MIN(KWHGEN) OVER (ORDER BY TIMESTAMP DESC)
           INTO VAL_ID_MED, VAL_KWHGEN 
           FROM T_measures_TP_NEW 
           WHERE ROWID = RowIdTable(i);

           IF KWHGENTable(i) < 0
              THEN UPDATE T_MEASURES_TP_NEW 
              SET KWHGEN = VAL_KWHGEN 
              WHERE  autoin = VAL_autoin;
           END IF;
       END LOOP;
    END AFTER STATEMENT;    

END;
/

答案 2 :(得分:0)

好的,我确实有一个解决方案:

1.-创建一个记录新插入数据的包(BEFORE)

create or replace PACKAGE PCK_MEDIDAS_TP AS 
TYPE DATOS_MEDIDAS_TP IS RECORD(
v_id_sede NUMBER (10,0),
v_id_med NUMBER (10,0),
v_kwhGEN NUMBER (21,2),
v_timestamp TIMESTAMP
);

type T_MEDTP is table of DATOS_MEDIDAS_TP index by binary_integer;

tabla_medidas_tp T_MEDTP;

END PCK_MEDIDAS_TP;

2.-在每一行(BEFORE)创建一个过程来读取新的插入数据,然后将它们记录到de package的表中。

create or replace TRIGGER "CIRCU3".D_MEDIDAS_TP_test
BEFORE INSERT ON T_MEDIDAS_TP_NEW
FOR EACH ROW
DECLARE
Indice binary_integer; 
BEGIN
--AUTOINCREMENTAL DEL CAMPO ID_MEDIDAS
SELECT T_MEDIDAS_TP_NEW_SEQ.NEXTVAL INTO :NEW.id_MEDIDAS_OLD FROM DUAL;

Indice:= PCK_MEDIDAS_TP.tabla_medidas_tp.COUNT+1;
PCK_MEDIDAS_TP.tabla_medidas_tp(Indice).v_id_sede := :NEW.ID_SEDE;
PCK_MEDIDAS_TP.tabla_medidas_tp(Indice).v_id_med := :NEW.ID_MEDIDAS;
PCK_MEDIDAS_TP.tabla_medidas_tp(Indice).v_kwhGEN := :NEW.KWHGEN;
PCK_MEDIDAS_TP.tabla_medidas_tp(Indice).v_timestamp := :NEW.TIMESTAMP;
IF :NEW.KWHGEN <0 THEN
DBMS_OUTPUT.put_line('first trigger:'     ||:NEW.ID_MEDIDAS||','||:NEW.ID_SEDE||','||:NEW.TIMESTAMP);
-- INSERT INTO TEST_TRIGGER VALUES ('100', :NEW.KWHGEN, SYSDATE);
--ELSE DBMS_OUTPUT.PUT_LINE('¿?');
END IF;
END;

3.-创建一个声明程序(AFTER),在那里你可以检查你的情况,在我的情况下,如果kwhgen <0。如果是,我将读取原始tbale中的上一条记录并使用taht值更新插入记录。

create or replace TRIGGER D_MEDIDAS_TP_TEST_STATEMENT 
AFTER INSERT ON T_MEDIDAS_TP_NEW 
DECLARE
Indice binary_integer;
s_id_sede NUMBER (10,0);
s_id_med NUMBER (10,0);
s_kwhGEN NUMBER (21,2);
s_timestamp TIMESTAMP;
BEGIN
FOR Indice in 1..PCK_MEDIDAS_TP.tabla_medidas_tp.count LOOP
DBMS_OUTPUT.put_line('second trigger: kwhgen:     '||PCK_MEDIDAS_TP.tabla_medidas_tp(Indice).v_kwhGEN||', id_sede:     '||PCK_MEDIDAS_TP.tabla_medidas_tp(Indice).v_id_sede);
IF PCK_MEDIDAS_TP.tabla_medidas_tp(Indice).v_kwhGEN <0 THEN
DBMS_OUTPUT.put_line('second trigger: v_kwhGEN is negative');
SELECT prev_KWHGEN INTO s_kwhgen
from(
SELECT LEAD (KWHGEN,1) over (ORDER BY id_medidas desc) as prev_KWHGEN
FROM T_MEDIDAS_TP_NEW WHERE ID_SEDE =     PCK_MEDIDAS_TP.tabla_medidas_tp(Indice).v_id_sede
ORDER BY id_medidas DESC) where rownum =1;
INSERT INTO TEST_TRIGGER VALUES ('100', '5555', SYSDATE);
DBMS_OUTPUT.put_line('second trigger. KWHGEN: '||s_kwhGEN);
DBMS_OUTPUT.put_line('UPDATE');
UPDATE T_MEDIDAS_TP_NEW SET KWHGEN = S_KWHGEN WHERE ID_MEDIDAS =     PCK_MEDIDAS_TP.tabla_medidas_tp(Indice).v_id_med;
else DBMS_OUTPUT.put_line('¿?');
END IF;
END LOOP;
PCK_MEDIDAS_TP.tabla_medidas_tp.delete; -- vaciamos la tabla
END;