我正在尝试在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'
任何帮助都是好人。
答案 0 :(得分:2)
一个选项是编写一个过程,以调用是否应删除表中的一行,而不是直接发出DELETE
语句。在该过程中,子节点首先被重定位,然后节点最终被删除。但是,这可能需要您使用该表来更改应用程序。
或者将表重命名以将其放入“背景”。
ALTER TABLE sucursal
RENAME TO sucursal_t;
然后使用重命名之前创建的表名称创建一个视图。这样就将视图留在了“前景”中。
CREATE VIEW sucursal
AS
SELECT codsuc,
ganancia,
sucpadre
FROM sucursal_t;
您现在可以在该视图上放置一个INSTEAD OF
触发器来拦截DELETE
。触发器首先重新定位要删除的节点的子节点,然后在“后台”表中删除该节点。
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;
/
这样,您现有的代码仍可以像以前一样使用该表。