Создать триггер для вставки в другую таблицу

У меня есть некоторые проблемы с выполнением триггера ниже:

CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW 

DECLARE

varReadNo   Int;
varMeterID  Int;
varCustID   Varchar(10);

BEGIN 

SELECT SeqReadNo.CurrVal INTO varReadNo FROM DUAL;

Select MeterID INTO varMeterID
From Reading 
Where ReadNo = varReadNo;

Select CustID INTO varCustID
From Address A
Join Meter M 
on A.postCode = M.postCode
Where M.MeterID = varMeterID;

INSERT INTO BILL VALUES 
(SEQBILLNO.NEXTVAL, SYSDATE, 'UNPAID' , 100 , varCustID , SEQREADNO.CURRVAL); 

END;

Сообщение об ошибке:

* Причина: триггер (или определенная пользователем функция plsql, на которую ссылается этот оператор) попытался просмотреть (или изменить) таблицу, которая была в середине процесса изменения оператором, который ее вызвал.

* Действие: переписать триггер (или функцию), чтобы он не читал эту таблицу.

Значит ли это, что я не собираюсь извлекать какие-либо подробности из таблицы Reading?

Я считаю, что проблема возникает, когда я получаю данные из чтения таблицы, когда он вставляет значение:

SELECT SeqReadNo.CurrVal INTO varReadNo FROM DUAL;

Select MeterID INTO varMeterID
From Reading 
Where ReadNo = varReadNo; 

Это в любом случае, чтобы решить это? Или есть лучший способ сделать это? Мне нужно вставить новую строку в таблицу BILL после входа в чтение таблицы, где ReadNo нужно ссылаться на ReadNo, который я просто вставляю.

4 ответа

Решение

Вы не можете получить записи из той же таблицы в триггере строки. Вы можете получить доступ к значениям из фактической записи, используя:new и:old (это ваш случай?). Затем триггер можно переписать в

CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW 

DECLARE

  varCustID   Varchar(10);

BEGIN 

  Select CustID INTO varCustID
    From Address A
    Join Meter M 
      on A.postCode = M.postCode
    Where M.MeterID = :new.MeterID;

  INSERT INTO BILL VALUES 
  (SEQBILLNO.NEXTVAL, SYSDATE, 'UNPAID' , 100 , varCustID , SEQREADNO.CURRVAL); 

END;

Если вам нужно запросить другую запись из таблицы READING, вы должны использовать комбинацию триггеров операторов, триггеров строк и коллекции PLSQL. Хороший пример этого на AskTom.oracle.com

Мы можем объединить вставить и выбрать заявление

CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW 

DECLARE

varCustID   Varchar(10);

BEGIN 

 insert into bill 
 values 
 select SEQBILLNO.NEXTVAL, 
        SYSDATE, 
        'UNPAID' , 
        100 ,
        CustID,SEQREADNO.CURRVAL 
 From  Address A
 Join  Meter M 
 on    A.postCode = M.postCode
 Where M.MeterID = :new.MeterID; 

END;

попробуйте приведенный выше код.

Добавьте обработку исключений в свой триггер и посмотрите, что происходит, так как вам будет легко отслеживать исключения.

CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW 

DECLARE

  varCustID   Varchar(10);

BEGIN 

  -- your code

EXCEPTION
    WHEN NO_DATA_FOUND
    THEN
        DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20299)));
    WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20298)));

END;

Убедитесь, что у вас есть необходимые разрешения на все таблицы и доступ к последовательностям, которые вы используете во вставке.

Я не делал Oracle некоторое время, но вы также можете попробовать запросить dba_errors (или all_errors), чтобы попытаться получить больше информации о том, почему ваш SP не компилируется.

Что-то под мелодию:

SELECT * FROM dba_errors WHERE owner = 'THEOWNER_OF_YOUR_SP';
Другие вопросы по тегам