更新同一表中的值的 PL/SQL 插入和删除触发器

Posted

技术标签:

【中文标题】更新同一表中的值的 PL/SQL 插入和删除触发器【英文标题】:PL/SQL insert and delete trigger that updates value in same table 【发布时间】:2021-04-02 08:40:56 【问题描述】:

我有下表:

CREATE TABLE individuo(
  codigo NUMBER(8) PRIMARY KEY,
  nombre VARCHAR2(20) NOT NULL,
  valor NUMBER(8) NOT NULL CHECK (valor > 0),
  padre NUMBER(8) REFERENCES individuo,
  nro_hijos NUMBER(8) NOT NULL CHECK (nro_hijos >=0),
  CHECK(padre <> codigo)
);

其中 padre 表示 父亲nro_hijos 表示 孩子的数量

我需要一个触发器,当我插入删除padre IS NOT NULL所在的行时,它会相应地增加或减少nro_hijos .

我试过了:

CREATE OR REPLACE TRIGGER individuo_parent_increment
AFTER INSERT OR DELETE ON INDIVIDUO FOR EACH ROW WHEN (NEW.padre IS NOT NULL)
    BEGIN
        IF INSERTING THEN
            UPDATE INDIVIDUO SET NRO_HIJOS = NRO_HIJOS + 1 WHERE CODIGO = :NEW.PADRE;
        END IF;
    END;

但它是 ORA-04091(表个体正在变异,触发器/函数可能看不到它)

我也尝试使用COMPOUND TRIGGER,但发生了同样的错误。

我已经设置了一个不同的触发器

CREATE OR REPLACE TRIGGER individuo_initial_children
BEFORE INSERT ON INDIVIDUO
    FOR EACH ROW
    BEGIN
        :NEW.NRO_HIJOS := 0;
    END;

【问题讨论】:

我认为在另一个表中保存孩子的信息以及与当前表的主外键关系,并在需要孩子数量时为单个父亲计算新创建的表。例如。为了数据库设计,放弃创建计数触发器。 我需要一个触发器,这是一项学术任务:c 【参考方案1】:

我最终使用复合触发器 [1][2] 进行了以下操作:

CREATE OR REPLACE TRIGGER individuo_compound_trigger
FOR INSERT ON INDIVIDUO
COMPOUND TRIGGER

    -- Create a list of number
    TYPE number_arr IS TABLE OF INDIVIDUO.PADRE%TYPE
    INDEX BY BINARY_INTEGER;
    dads number_arr;

    -- The other trigger I needed
    BEFORE EACH ROW IS
    BEGIN
        :NEW.NRO_HIJOS := 0;
    END BEFORE EACH ROW;

    -- Store all affected padre.
    AFTER EACH ROW IS BEGIN
        IF :NEW.PADRE IS NOT NULL THEN
            dads(dads.COUNT + 1) := :NEW.PADRE;
        END IF;
    END AFTER EACH ROW;

    -- Loop through them and update them here:
    AFTER STATEMENT IS BEGIN
        FOR dad IN 1..dads.COUNT
            LOOP
                UPDATE INDIVIDUO SET NRO_HIJOS = NRO_HIJOS + 1 WHERE CODIGO = dads(dad);
            END LOOP;
    END AFTER STATEMENT;

END individuo_compound_trigger;

注意:这是一项学术作业,我被专门要求创建触发器,我不知道这是否是用于其他目的的好解决方案。

【讨论】:

【参考方案2】:

复合触发器是正确的解决方案,如果需要保持运行的子节点总数。一个更好的设计(恕我直言)将是在需要时导出它,也许是在一个视图中。作为一项任务,很高兴看到您寻找并找到了这种方法。我会做一点小小的改变。您应该停止思考循环。而不是循环遍历数组,只需使用 FORALL 结果是一条语句来处理所有更新。

-- Update NRO_HIJOS for all dads in array 
after statement is begin
    forall dad in 1..dads.count
            update individuo 
               set nro_hijos = nro_hijos + 1 
             where codigo = dads(dad);
end after statement;

【讨论】:

以上是关于更新同一表中的值的 PL/SQL 插入和删除触发器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用触发器在同一张表中插入新行(Oracle PL/SQL 10G)?

PL/SQL 触发器插入下一个值

使用 PL/SQL 在触发器中中止插入/更新操作

PL / SQL触发器在更新或插入后更新同一个表

pl/sql 触发器完整性约束问题

pl/sql-create trigger on a table - 每当在同一个表中插入新记录时,应更新表的另一列