【问题标题】:Oracle Compound Trigger Mutation TableOracle 复合触发器突变表
【发布时间】:2015-09-18 12:31:30
【问题描述】:

我正在尝试创建一个复合触发器来避免突变问题。 我有一个表和一个执行事务插入的 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;

但是变异错误在跟着我 ;-)

【问题讨论】:

    标签: oracle triggers oracle12c mutation


    【解决方案1】:

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

    【讨论】:

    • 对不起Shravan Yadav,我完全不理解你,你能解释一下吗?我是触发器的新手。非常感谢。触发器中的第一个选择允许获取所有最后记录的字段值以在 IF 中为 True 的情况下使用它们。
    【解决方案2】:

    你只定义了一个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;
    /
    

    【讨论】:

    • 谢谢 Wernfried,我正在测试它。
    【解决方案3】:

    好的,我确实有办法:

    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包的表中。

    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.- 创建一个语句过程(之后),您可以在其中检查您的情况,在我的情况下,如果 kwhgen

    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;
    

    【讨论】:

      猜你喜欢
      • 2017-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-01
      • 2016-05-21
      • 2020-12-30
      相关资源
      最近更新 更多