ORACLE在包含触发条件的表的INSERT和UPDATE上触发

时间:2015-07-14 15:48:43

标签: sql oracle plsql triggers

我有一个配置表,其中包含用于控制应用程序中进程的记录。通常情况下,我会让应用程序控制该表,但是现在它是不可能的(没有钱,没有时间等)。因此,目前该表将由SQL Developer等客户端管理。为了确保正确填充表,我需要一个触发器,因为检查约束不适用于自定义函数。 INSERT上的触发器工作得很好,但我在UPDATE上遇到触发器的问题,因为触发器检查的所有条件都在表本身中,我从ORACLE得到一个错误,表该表正在更新,所以触发器无法触发。

表包含以下列:

ID, SOURCE_SYSTEM, TARGET_SYSTEM, TABLE_ID, VALID_FROM, VALID_THROUGH
 1,             2,             3,      455, 01.12.2011.    02.11.2013

条件如下:

  • 不能拥有相同SOURCE_SYSTEM,TARGET_SYSTEM和TABLE_ID的新记录以及与现有记录重叠的日期 - NEW.VALID_FROM和NEW.VALID_THROUGH必须在现有期间之外。例如 - 两者都必须是< 01.12.2011或> 2013年2月11日

所以我的问题是,有没有办法让这项工作也在更新?我已经读过关于使用物化视图的触发器,但我想我可能会遇到表和视图之间的数据不同步的问题。

感谢您的帮助! 人

PS。使用Oracle Release 12.1.0.2.0

更新:这是on INSERT触发器:

create or replace 
trigger SINGLE_QUELLSYSTEM_INSERT
BEFORE INSERT ON CTL_WEBADMIN_ABGLEICH FOR EACH ROW
DECLARE 
    v_count_rows NUMBER;
BEGIN
  dbms_output.ENABLE (buffer_size => NULL);
  dbms_output.put_line('Start...');

  IF(:NEW.CLDB_QUELLSYSTEM_ID = :NEW.CLDB_ZIELSYSTEM_ID) THEN
    RAISE_APPLICATION_ERROR(-20336, 'Quellsystem ist gleich dem Zielsystem. Bitte, korrigieren Sie Ihre Abfrage.');
  END IF;

  IF(:NEW.GUELTIG_BIS < :NEW.GUELTIG_VON) THEN
    RAISE_APPLICATION_ERROR(-20338, 'Datum BIS liegt vor Datum VON. Bitte, korrigieren Sie Ihre Abfrage.');
  END IF;     

  SELECT COUNT(*) INTO v_count_rows FROM CTL_WEBADMIN_ABGLEICH;
  dbms_output.put_line('Anzahl der Zeilen in der Tabelle CTL_WEBADMIN_ABGLEICH: ' || v_count_rows);
  IF (v_count_rows >=1 ) THEN
    dbms_output.put_line('Mehrere Zeilen in der Tabelle CTL_WEBADMIN_ABGLEICH vorhanden. Checking trigger condition...');
    -- FOR r in (SELECT DISTINCT CLDB_QUELLSYSTEM_ID,CLDB_WEBADMIN_TABLE_ID, GUELTIG_BIS, GUELTIG_VON FROM CTL_WEBADMIN_ABGLEICH where GUELTIG_VON >= sysdate )
    FOR r in (SELECT DISTINCT CLDB_QUELLSYSTEM_ID,CLDB_WEBADMIN_TABLE_ID, GUELTIG_BIS, GUELTIG_VON FROM CTL_WEBADMIN_ABGLEICH)
    LOOP
      IF ((r.CLDB_QUELLSYSTEM_ID != :NEW.CLDB_QUELLSYSTEM_ID OR r.CLDB_QUELLSYSTEM_ID = :NEW.CLDB_QUELLSYSTEM_ID) and r.CLDB_WEBADMIN_TABLE_ID = :NEW.CLDB_WEBADMIN_TABLE_ID ) THEN
      dbms_output.put_line('Ein anderes Quellsystem wurde für das System: ' || r.CLDB_QUELLSYSTEM_ID || ' schon spezifiziert. Checking Gültigkeit...');
        IF (r.GUELTIG_BIS is null OR (:NEW.GUELTIG_BIS >= r.GUELTIG_VON AND :NEW.GUELTIG_BIS <= r.GUELTIG_BIS) OR 
            (:NEW.GUELTIG_VON >= r.GUELTIG_VON AND :NEW.GUELTIG_VON <= r.GUELTIG_BIS) OR 
            (:NEW.GUELTIG_VON <= r.GUELTIG_VON AND :NEW.GUELTIG_BIS >= r.GUELTIG_BIS)) THEN
            RAISE_APPLICATION_ERROR(-20337, 'Gültigkeitsbereiche mit schon existierenden Einträgen kollidieren!');
        END IF;
      END IF;
    END LOOP;
  END IF;
END;

on UPDATE触发器是相同的,除了声明部分,

create or replace 
trigger SINGLE_QUELLSYSTEM_UPDATE
BEFORE UPDATE ON CTL_WEBADMIN_ABGLEICH FOR EACH ROW ...

我得到的错误:

ORA-04091: table CLDBDEF.CTL_WEBADMIN_ABGLEICH is mutating, trigger/function may not see it

1 个答案:

答案 0 :(得分:1)

  

ORA-04091:表CLDBDEF.CTL_WEBADMIN_ABGLEICH正在变异,   触发器/功能可能看不到它

当语句导致触发器触发并且该触发器引用导致触发器的表时,会发生

Mutating Error

如何避免:

  1. 请勿使用触发器
  2. 使用“after”或“而不是”触发器
  3. 重新执行触发器语法
  4. 使用自主交易
  5. 参考: -

    Fix Oracle Mutating error