【问题标题】:PL/SQL insert and delete trigger that updates value in same table更新同一表中的值的 PL/SQL 插入和删除触发器
【发布时间】: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

标签: sql oracle plsql triggers


【解决方案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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-27
      • 1970-01-01
      • 2011-11-25
      • 1970-01-01
      • 1970-01-01
      • 2012-09-19
      相关资源
      最近更新 更多