Как я могу решить эту ошибку в PLSQL / DELETE TRIGGER error - PullRequest
0 голосов
/ 25 сентября 2018

Я пытаюсь написать код в plsql, который делает что-то вроде этого: перед тем, как удалить строку, этот триггер проверит, есть ли у строки дочерние элементы, в этом случае дочерние элементы становятся дочерними элементами своего деда, а затем строкиприступает к удалению.

Итак, вот что у меня сейчас:

CREATE TABLE sucursal
(
    codsuc     NUMBER (8) PRIMARY KEY,
    ganancia   NUMBER (8) NOT NULL CHECK (ganancia > 0),
    sucpadre   NUMBER (8) REFERENCES sucursal
);

CREATE OR REPLACE TRIGGER borrar_sucursal
    BEFORE DELETE
    ON sucursal
    FOR EACH ROW
    WHEN (old.sucpadre IS NOT NULL)
BEGIN
    DBMS_OUTPUT.PUT_LINE ('Bueno pues lo intente');
    hijo_de_abuelo (:old.codsuc);
END;
/

CREATE OR REPLACE PROCEDURE hijo_de_abuelo (codigo IN sucursal.codsuc%TYPE)
IS
    gato   sucursal.sucpadre%TYPE;
BEGIN
    SELECT sucpadre
      INTO gato
      FROM sucursal
     WHERE codsuc = codigo;

    FOR gallo IN (SELECT *
                    FROM sucursal
                   WHERE sucpadre = codigo)
    LOOP
        UPDATE sucursal
           SET sucpadre = gato
         WHERE codsuc = gallo.codsuc;
    END LOOP;
END;
/

Итак, вот что происходит, когда я пытаюсь удалить строку в консоли SQL:

SQL> delete from sucursal where codsuc = 2;
Bueno pues lo intente
delete from sucursal where codsuc = 2
            *
ERROR at line 1:
ORA-04091: table PANCRACI0.SUCURSAL is mutating, trigger/function may not see
it
ORA-06512: at "PANCRACI0.HIJO_DE_ABUELO", line 7
ORA-06512: at "PANCRACI0.BORRAR_SUCURSAL", line 3
ORA-04088: error during execution of trigger 'PANCRACI0.BORRAR_SUCURSAL'

Любая помощь будет отличными парнями.

1 Ответ

0 голосов
/ 25 сентября 2018

Один из вариантов - написать процедуру для вызова, если строка в таблице должна быть удалена, а не напрямую вызывать оператор DELETE.В этой процедуре дочерние элементы сначала перемещаются, прежде чем узел окончательно удаляется.Однако для этого может потребоваться изменить приложения с помощью таблицы.

В качестве альтернативы переименуйте таблицу, чтобы поместить ее в «фон».

ALTER TABLE sucursal
            RENAME TO sucursal_t;

Затем создайте представление с тем же именемТаблица была до того, как вы ее переименовали.Это оставляет представление на «переднем плане».

CREATE VIEW sucursal
AS
SELECT codsuc,
       ganancia,
       sucpadre
       FROM sucursal_t;

В этом представлении теперь можно разместить триггер INSTEAD OF для перехвата DELETE s.Триггер сначала перемещает дочерние узлы узла, который собирается удалить, а затем удаляет узел в «фоновой» таблице.

CREATE OR REPLACE TRIGGER borrar_sucursal
                          INSTEAD OF DELETE
                          ON sucursal
                          FOR EACH ROW
BEGIN
    DBMS_OUTPUT.PUT_LINE('Bueno pues lo intente');

    UPDATE sucursal_t
           SET sucpadre = :old.sucpadre
           WHERE sucpadre = :old.codsuc;

    DELETE FROM sucursal_t
           WHERE codsuc = :old.codsuc;
END;
/

db <> fiddle

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

...