【问题标题】:How can I solve this error in PLSQL / DELETE TRIGGER error如何解决 PLSQL / DELETE TRIGGER 错误中的此错误
【发布时间】:2018-09-25 21:39:30
【问题描述】:

我正在尝试在 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'

任何帮助都会很棒。

【问题讨论】:

标签: oracle plsql database-trigger


【解决方案1】:

一个选项是编写一个过程来调用如果表中的一行应该被删除,而不是直接发出DELETE 语句。在该过程中,子节点在最终删除节点之前首先被重新定位。但是,这可能需要您使用该表更改应用程序。

或者重命名表格以将其放入“背景”。

ALTER TABLE sucursal
            RENAME TO sucursal_t;

然后创建一个与重命名之前的表同名的视图。这会将视图留在“前景”中。

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

您现在可以在该视图上放置INSTEAD OF 触发器来拦截DELETEs。触发器首先重新定位即将被删除的节点的子节点,然后删除“背景”表中的节点。

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

这样您现有的代码仍然可以像以前一样使用该表。

【讨论】:

    猜你喜欢
    • 2017-10-06
    • 1970-01-01
    • 2014-03-28
    • 1970-01-01
    • 2017-12-12
    • 2012-02-14
    • 2015-04-12
    • 2016-06-21
    • 2020-11-16
    相关资源
    最近更新 更多