因此,您要强制执行的规则是TABLE_1只能在TABLE_2中某列的值为零或更小时才引用TABLE_2。嗯....让我们来梳理触发逻辑,然后我们将讨论这个规则。
触发应该是这样的:
CREATE or replace TRIGGER "New_Trigger"
AFTER INSERT OR UPDATE ON "Table_1"
FOR EACH ROW
declare
n "Table_2"."number".type%;
BEGIN
Select "Table_2"."number"
into n
from "Table_2"
WHERE "Table_2"."ID" = :new.FK_Table_2_ID;
if n > 0
THEN RAISE_APPLICATION_ERROR(-20000, 'this is not allowed');
end if;
END;
请注意,您的错误信息应包括一些有用的信息,如TABLE_1主键,值当你插入或更新表中的多行的。
你在这里要做的是强制一种称为ASSERTION的约束。断言是在ANSI标准中指定的,但是Oracle尚未实现它们。其他任何关系型数据库也没有涉及到。
断言是有问题的,因为它们是对称的。也就是说,该规则还需要在TABLE_2上实施。目前您在TABLE_1中创建记录时检查规则。假设稍后用户更新TABLE_2。NUMBER,因此它大于零:您的规则现在已被破坏,但您不会知道它被破坏,直到有人问题完全不相关 UPDATE TABLE_1,然后将失败。呸。
那么,该怎么办?
如果规则实际上是
TABLE_1只能引用TABLE_2如果 TABLE_2.NUMBER为零
那么你可以强制执行,而不触发。
- 在TABLE_2上为(ID,NUMBER)添加一个UNIQUE约束;您需要额外的约束,因为ID仍然是TABLE_2的主键。
- 在TABLE_1上添加名为TABLE_2_NUMBER的虚拟列。默认它为零,并有一个检查约束来确保它始终为零。 (如果您使用的是11g,则应考虑使用虚拟列。)
- 更改TABLE_1上的外键,因此(FK_Table_2_ID,TABLE_2_NUMBER)引用唯一约束而不是TABLE_2的主键。
- 放下“New_Trigger”触发器;您不再需要它,因为外键会阻止任何人将TABLE_2.NUMBER更新为零以外的值。
但是,如果规则是真的,因为我制定了它的顶部即
TABLE_1只能引用TABLE_2如果 TABLE_2.NUMBER不大于零(即负值都还好)
然后,您需要另一个触发器,这次在TABLE_2上,以强制执行规则的另一端。
CREATE or replace TRIGGER "Assertion_Trigger"
BEFORE UPDATE of "number" ON "Table_2"
FOR EACH ROW
declare
x pls_integer;
BEGIN
if :new."number" > 0
then
begin
Select 1
into x
from "Table_1"
WHERE "Table_1"."FK_Table_2_ID" = :new.ID
and rownum = 1;
RAISE_APPLICATION_ERROR(-20001, :new.ID
||' has dependent records in Table_1');
exception
when no_data_found then
null; -- this is what we want
end;
END;
这触发将不会允许,如果它被记录TABLE_2引用您更新TABLE_2.NUMBER到大于零的值。只有在UPDATE语句触及TABLE_2.NUMBER以最小化执行查找的性能影响时才会触发。
来源
2011-04-27 05:25:49
APC
不知道为什么你称这是一个独特的约束。 – APC 2011-04-27 05:45:57
也许如果您可以根据人员和部门重新制定您的示例,而不是使用Table_1和Table_2,则您的要求会变得更加清晰。目前我无法弄清楚Table_1应该是一个新人,还是一个新部门,或者是一个新的person_department_assignment ... – 2011-04-27 09:09:40