Oracle 数据库 - 确定什么 table 触发了触发器
Oracle database - determine what table triggered a trigger
我正在使用 Oracle Express 12c。我创建的 table 之一有一个关联的触发器,阻止它直接更新其中一个列。但是即使另一个应该有这种访问权限的 table 尝试这样做,它也会触发。
例如:
我有 tables A 和 B,B 有一个将它链接到 A 的外键。我有意将 A 的属性之一添加到 B。一个触发器,我们称之为 UPD_FROM_B, 阻止 B 更新这个属性。另一个,UPD_FROM_A,如果在 A 上更新了这个属性,应该在 B 上更新这个属性。现在 UPD_FROM_B 阻止 UPD_FROM_A 做它应该做的事情。
或者通过一个工作示例:
有两个table:客户和订单。 客户可以有多个订单,但是一个订单只有一个客户。为了项目,我只好把customer_name放在订单上,尽管每个订单都有customer_id作为外键。
一个触发器 - UPD_NAME_ORDER 阻止 order 更新
customer_name,另一个 - UPD_NAME_CUST 在 顺序的相应行中更新此列 table 每当 customer_name 在 customer
中更新时
如何确定哪个 table 触发了操作并允许其中一个更新,但仍然阻止另一个更新?
从表面上看,我知道这样做的方法是使用包变量作为门键并在 2 个触发器之间共享它。触发器 A 将在嵌套更新 B 之前设置状态变量。触发器 B 将检查 A 是否设置了 var,如果是,则更新成功,如果不是,则 B 知道 A 不是调用者,它应该阻止更新。
此外,我假设您的意图是实现一个“UPDATE CASCADE”触发器以根据父更新更新子记录外键值,在更新时保留关系FK 值。如果是这样,您必须谨慎使用这种方法,只有在您禁止多行更新时它才能正常工作。
首先是一个包和状态变量:
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 将为每个父值执行触发器,导致某些子值根据链接的前后值多次更新。
我认为您必须只更改触发器 UPD_FROM_B。
首先,当父键和外键相等时,select 来自 table A 的列的值,然后将此值与来自 table 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;
我正在使用 Oracle Express 12c。我创建的 table 之一有一个关联的触发器,阻止它直接更新其中一个列。但是即使另一个应该有这种访问权限的 table 尝试这样做,它也会触发。
例如:
我有 tables A 和 B,B 有一个将它链接到 A 的外键。我有意将 A 的属性之一添加到 B。一个触发器,我们称之为 UPD_FROM_B, 阻止 B 更新这个属性。另一个,UPD_FROM_A,如果在 A 上更新了这个属性,应该在 B 上更新这个属性。现在 UPD_FROM_B 阻止 UPD_FROM_A 做它应该做的事情。
或者通过一个工作示例:
有两个table:客户和订单。 客户可以有多个订单,但是一个订单只有一个客户。为了项目,我只好把customer_name放在订单上,尽管每个订单都有customer_id作为外键。
一个触发器 - UPD_NAME_ORDER 阻止 order 更新 customer_name,另一个 - UPD_NAME_CUST 在 顺序的相应行中更新此列 table 每当 customer_name 在 customer
中更新时如何确定哪个 table 触发了操作并允许其中一个更新,但仍然阻止另一个更新?
从表面上看,我知道这样做的方法是使用包变量作为门键并在 2 个触发器之间共享它。触发器 A 将在嵌套更新 B 之前设置状态变量。触发器 B 将检查 A 是否设置了 var,如果是,则更新成功,如果不是,则 B 知道 A 不是调用者,它应该阻止更新。
此外,我假设您的意图是实现一个“UPDATE CASCADE”触发器以根据父更新更新子记录外键值,在更新时保留关系FK 值。如果是这样,您必须谨慎使用这种方法,只有在您禁止多行更新时它才能正常工作。
首先是一个包和状态变量:
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 将为每个父值执行触发器,导致某些子值根据链接的前后值多次更新。
我认为您必须只更改触发器 UPD_FROM_B。 首先,当父键和外键相等时,select 来自 table A 的列的值,然后将此值与来自 table 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;