更新同一表中的值的 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 插入和删除触发器的主要内容,如果未能解决你的问题,请参考以下文章