Oracle数据库 - 确定哪个表触发了触发器

时间:2017-01-05 21:28:34

标签: sql oracle plsql triggers oracle12c

我正在使用Oracle Express 12c。我创建的其中一个表有一个关联的触发器,可以防止它直接更新其中一个列。但即使另一个应该具有此类访问权限的表尝试执行此操作,它也会触发。

例如:

我有表A和B,B有一个将它链接到A的外键。我故意将一个属性从A添加到B.一个触发器,我们称之为UPD_FROM_B,阻止B更新该属性。另一个UPD_FROM_A应该在B上更新此属性,如果它在A上更新。现在UPD_FROM_B阻止UPD_FROM_A做它应该做的事情。

或通过一个工作示例:

有两个表:客户订单客户可以有多个订单,但一个订单只有一个客户。为了项目,我不得不在订单上加上 customer_name ,即使每个订单都有 customer_id 作为外键。

一次触发 - UPD_NAME_ORDER 阻止订单更新 每当 customer_name 更新时, customer_name ,另一个 - UPD_NAME_CUST 会在订单表的相应行中更新此列在客户

如何确定哪个表触发了操作并允许UPDATE为一个,但仍然阻止了另一个?

2 个答案:

答案 0 :(得分:2)

我认为您必须仅更改触发器UPD_FROM_B。 首先,当父键和外键相等时,从表A中选择列的值,然后将此值与表B中的列值进行比较。如果此值等于您的触发器,则允许执行此更新,否则不会。您编写此代码如下:

CREATE TRIGGER UPD_FROM_B before update on B
DECLARE
 val A.upd_column%TYPE; 
BEGIN
    select A.upd_column into val
    where A.ID=B.FKID
    if val=B.upd_column then

        RAISE;
    else ......
    end if;
END;

答案 1 :(得分:1)

从表面上看,我知道这样做的方法是使用包变量作为门键并在2个触发器之间共享它。触发器A将在嵌套更新B之前设置状态变量。触发器B将检查A是否设置var,如果是,则更新成功,否则,B知道A不是调用者,它应该阻止更新。

此外,我假设您的目的是实现“ UPDATE CASCADE ”触发器,以根据父更新更新子记录外键值,同时在更新FK值时保留关系。如果是这样,你必须小心这种方法,它只有在你不允许多行更新时才能正常工作。

首先是一个包和状态var:

CREATE PACKAGE IsUpdating IS
  A number;
END;

在触发器A的顶部执行类似下面的操作。异常处理程序是一个“finally”块,它总是执行以避免在更新错误的情况下将包变量保留为无效状态:

CREATE TRIGGER A_UPD_CASCADE after update on A for each row
BEGIN
    IsUpdating.A := 1;
    update B set B.FKID = :new.FKID WHERE B.FKID = :old.FKID;
    IsUpdating.A := 0;

EXCEPTION
    WHEN OTHERS
    THEN
        IsUpdating.A := 0;
        RAISE;
END;

内部触发器B执行此操作:

CREATE TRIGGER B_UPD_CASCADE before update on B
BEGIN
    if IsUpdating.A != 1 then
        -- Disallow update since it is coming from B alone
        RAISE;
    end if;
END;

CASCADE UPDATE的缺陷是在单个语句中使用多行父更新,Oracle将为每个父值执行触发器,导致某些子值根据值前后链接多次更新。