Oracle 唯一约束 - 触发器检查新关系中的属性值
您好,我在获取正确的 sql 语法时遇到问题。我想创建一个唯一的约束,它查看新添加的外键,查看新相关实体的一些属性来决定是否允许这种关系。
CREATE or replace TRIGGER "New_Trigger"
AFTER INSERT OR UPDATE ON "Table_1"
FOR EACH ROW
BEGIN
Select "Table_2"."number"
(CASE "Table_2"."number" > 0
THEN RAISE_APPLICATION_ERROR(-20000, 'this is not allowed');
END)
from "Table_1"
WHERE "Table_2"."ID" = :new.FK_Table_2_ID
END;
编辑:APC 的答案非常全面,但是让我认为我的做法是错误的。
情况是我有一张具有不同权限级别的人员表,我想检查这些权限级别,例如用户“鲍勃”具有低级别权限,他试图成为需要高权限的部门负责人,因此系统阻止这种情况发生。
有一个后续问题提出了相关场景,但具有不同的数据模型。 在这里找到它< /a>.
Hi I'm having trouble getting my sql syntax correct. I want to create a unique constraint that looks at the newly added foreign key, looks at some properties of the newly related entity to decided if the relationship is allowed.
CREATE or replace TRIGGER "New_Trigger"
AFTER INSERT OR UPDATE ON "Table_1"
FOR EACH ROW
BEGIN
Select "Table_2"."number"
(CASE "Table_2"."number" > 0
THEN RAISE_APPLICATION_ERROR(-20000, 'this is not allowed');
END)
from "Table_1"
WHERE "Table_2"."ID" = :new.FK_Table_2_ID
END;
Edit: APC answer is wonderfully comprehensive, however leads me to think im doing it in the wrong way.
The situation is I have a table of people with different privilege levels, and I want to check these privilege levels, e.g. A user, 'Bob', has low level privileges and he tries to become head of department which requires requires high privileges so the system prevents this happening.
There is a follow-up question which poses a related scenario but with a different data model. Find it here.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因此,您要强制执行的规则是,如果 TABLE_2 中的某些列为零或更少,则 TABLE_1 只能引用 TABLE_2。嗯……先理清触发逻辑,然后再讨论规则。
触发器应如下所示:
请注意,当您在表中插入或更新多行时,错误消息应包含一些有用的信息,例如 TABLE_1 主键的值。
您在这里尝试执行的是强制执行一种称为 ASSERTION 的约束。断言是在 ANSI 标准中指定的,但 Oracle 尚未实现它们。其他 RDBMS 也没有做到这一点。
断言是有问题的,因为它们是对称的。也就是说,该规则也需要在 TABLE_2 上强制执行。此时,您检查在 TABLE_1 中创建记录时的规则。假设稍后某个用户更新了 TABLE_2.NUMBER,使其大于零:您的规则现在已被破坏,但您不会知道它已被破坏,直到有人对 TABLE_1 发出完全不相关的 UPDATE ,然后就会失败。恶心。
那么,该怎么办呢?
如果规则实际上是
,那么您可以在没有触发器的情况下强制执行它。
但如果规则真的像我在顶部制定的那样
那么您需要另一个触发器(这次是在 TABLE_2 上)来强制执行规则的另一端。
如果 TABLE_2.NUMBER 被 TABLE_2 中的记录引用,则此触发器将不允许您将 TABLE_2.NUMBER 更新为大于零的值。仅当 UPDATE 语句触及 TABLE_2.NUMBER 时才会触发,以尽量减少执行查找对性能的影响。
So the rule you want to enforce is that TABLE_1 can only reference TABLE_2 if some column in TABLE_2 is zero or less. Hmmm.... Let's sort out the trigger logic and then we'll discuss the rule.
The trigger should look like this:
Note that your error message should include some helpful information such as the value of the TABLE_1 primary key, for when you are inserting or updating multiple rows on the table.
What you are trying to do here is to enforce a type of constraint known as an ASSERTION. Assertions are specified in the ANSI standard but Oracle has not implemented them. Nor has any other RDBMS, come to that.
Assertions are problematic because they are symmetrical. That is, the rule also needs to be enforced on TABLE_2. At the moment you check the rule when a record is created in TABLE_1. Suppose at some later time a user updates TABLE_2.NUMBER so it is greater than zero: your rule is now broken, but you won't know that it is broken until somebody issues a completely unrelated UPDATE on TABLE_1, which will then fail. Yuck.
So, what to do?
If the rule is actually
then you can enforce it without triggers.
But if the rule is really as I formulated it at the top i.e.
then you need another trigger, this time on TABLE_2, to enforce it the other side of the rule.
This trigger will not allow you to update TABLE_2.NUMBER to a value greater than zero if it is referenced by records in TABLE_2. It only fires if the UPDATE statement touches TABLE_2.NUMBER to minimise the performance impact of executing the lookup.
不要使用触发器创建唯一约束或外键约束。 Oracle 对唯一键和外键有声明性支持,例如:
在列上添加唯一约束:
添加外键关系:
我不清楚您到底想用触发器实现什么目标 - 这有点混乱SQL 和 PL/SQL 混合在一起是行不通的,并且似乎引用了
"Table_2"
上的一列,而该列实际上并未被查询。一个好的经验法则是,如果您的触发器正在查询触发器所在的同一个表,那么它可能是错误的。
我不确定,但是您是否在追求某种有条件的外键关系?即“仅允许父行满足条件 x 的子行”?如果是这样,则问题出在数据模型中,应该在那里修复。如果您对您想要实现的目标提供更多解释,我们应该能够为您提供帮助。
Don't use a trigger to create a unique constraint or a foreign key constraint. Oracle has declarative support for unique and foreign keys, e.g.:
Add a unique constraint on a column:
Add a foreign key relationship:
I'm not clear on exactly what you're trying to achieve with your trigger - it's a bit of a mess of SQL and PL/SQL munged together which will not work, and seems to refer to a column on
"Table_2"
which is not actually queried.A good rule of thumb is, if your trigger is querying the same table that the trigger is on, it's probably wrong.
I'm not sure, but are you after some kind of conditional foreign key relationship? i.e. "only allow child rows where the parent satisfies condition x"? If so, the problem is in the data model and should be fixed there. If you provide more explanation of what you're trying to achieve we should be able to help you.