Мутирующая таблица в триггере перед - PullRequest
1 голос
/ 02 января 2012

Я пытаюсь использовать триггер, чтобы избежать удаления строки в таблице Products при некоторых обстоятельствах. Код следующий

CREATE TRIGGER trgPreventProductRemoval
    BEFORE DELETE ON Products
    FOR EACH ROW

    BEGIN
        DECLARE
            l_custid INTEGER;
        BEGIN
            SELECT count(*) INTO l_custid FROM Orders WHERE product = :old.prodDescription ;

            IF l_custid > 0 THEN
                raise_application_error (-20100, 'You can not delete a product that has active orders!');
            END IF;
        END;
    END;

Однако я получаю сообщение об ошибке: table ORDERS is mutating, trigger/function may not see it.

Как я могу это исправить?

РЕДАКТИРОВАТЬ-РЕШЕНИЕ: Я принял решение ниже, потому что это "политически корректно". Из-за некоторых «ограничений» я не смог его использовать и, наконец, нашел другой обходной путь. Смотрите решение, которое я опубликовал отдельно.

Ответы [ 4 ]

5 голосов
/ 02 января 2012

Использовать внешний ключ между заказами и таблицей продуктов вместо триггера.

0 голосов
/ 02 января 2012

Наконец, проблема решается удалением «ссылки» между Products и Orders.Ссылка была ON DELETE CASCADE во внешнем ключе промежуточной таблицы с именем SuplProd.При удалении ON DELETE CASCADE из ФК SuplProd таблица Orders перестала изменяться.

Чтобы использовать для удаления ON DELETE CASCADE, я просто добавил еще одну строку кода в триггере.код, сразу после END IF;

Итак, технически, этот обходной путь работает, делая необходимую таблицу неизменной.

0 голосов
/ 02 января 2012

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

Однако есть немного грязный, но простой способ обойти проблему:

  1. Создать вид формы select * from products.
  2. Скомпилируйте триггер в представлении, а не в таблице.
  3. Убедитесь, что триггер выполняет операции DML, которые вы фактически предназначали для таблицы (грязная часть).
  4. Выполняйте операции DML только с представлением, а не с таблицей.

Итак, что-то вроде этого должно работать.

create or replace view v_products as select * from products;

CREATE TRIGGER trgPreventProductRemoval
    BEFORE DELETE ON v_products
    FOR EACH ROW

    DECLARE

    l_custid INTEGER;

    BEGIN

       SELECT count(*) INTO l_custid 
         FROM Orders 
        WHERE product = :old.prodDescription;

        IF l_custid > 0 THEN
         raise_application_error (-20100, 'You can not delete a product that has active orders!');
        END IF;

       -- assumed, I don-t know the actual columns.
        delete from products where product = :new.product_id;

    END trgPreventProductRemoval;
0 голосов
/ 02 января 2012

Попробуйте использовать AUTONOMOUS_TRANSACTIONS:

http://docs.oracle.com/cd/B19306_01/server.102/b14220/transact.htm#i7733

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...