我在 Oracle 中执行某些触发器时遇到问题。
我有两种类型“t_movie”和“t_video”定义为
CREATE TYPE t_movie AS OBJECT(
name VARCHAR(20),
year INTEGER);
和
CREATE TYPE t_video AS OBJECT(
type CHAR,
movie REF t_movie);
我还有关联的表格
CREATE TABLE movies OF t_movie
CREATE TABLE videos OF t_video
如果我从表 movies 中删除一个元组,我将在另一个表中有一些元组引用不再存在的对象。我怎样才能避免这种情况?我认为触发器是必要的,但我不知道如何实现它。谁能帮帮我?
谢谢。
编辑:
我试过这样的触发器:
CREATE or REPLACE TRIGGER delete_movie_cascade
before delete on movies
for each row
DECLARE
movie_ref (REF t_movie);
BEGIN
movie_ref = ref :old;
dbms_output.put_line(deref(movie_ref).name);
DELETE FROM videos WHERE movie = movie_ref;
END;
但是,正如预期的那样,我得到了错误
Error(6,13): PLS-00103: Encountered the symbol "(" when expecting one of the following: constant exception <an identifier> <a double-quoted delimited-identifier> table long double ref char time timestamp interval date binary national character nchar
最佳答案
Oracle Objection Developer's documentation关于防止悬挂引用的谈话:
A
REF
column may be constrained with aREFERENTIAL
constraint similar to the specification for foreign keys.
不幸的是,文档没有提供实际的例子来说明如何做到这一点。 REFERENTIAL
的格式表明它是一个关键字,但结果却是转移注意力。
真正的解决方案是定义一个实际的外键,但改用对象引用。因此,根据您发布的代码,将 videos
的定义更改为:
CREATE TYPE t_video AS OBJECT(
type CHAR,
movie REF t_movie
);
/
CREATE TABLE videos OF t_video (
foreign key (movie) references movies
)
/
现在,如果您尝试删除被视频引用的电影,Oracle 将抛出 ORA-02292: integrity constraint
。
触发器永远不是对常规表或对象表强制执行外键约束的正确解决方案。因为
- 在 FOR EACH ROW 触发器中查询引用表效率低下,尤其是对于多行删除。外键针对此任务进行了优化。
- 由于读提交隔离级别的原因,该操作在多用户环境中是不安全的。当另一个用户在不同的 session 中添加子行时,触发器将通过我们的删除操作。
- 外键约束是标准。偏离标准是不好的做法,因为它使我们的代码更难维护。
- 触发器中强制执行的规则不会出现在数据字典中。这将使我们的同事感到困惑,阻止数据模型的逆向工程,并使优化器无法获得一些有用的信息来得出有效的执行计划。
关于sql - 删除时触发以避免悬空引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54384101/