触发删除操作,避免悬挂参考

时间:2019-01-27 00:32:46

标签: sql database oracle oracle11g user-defined-types

我在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

如果我从电影表中删除一个元组,那么我将在另一个表中有一些元组,其中引用了不再存在的对象。如何避免这种情况?我认为触发器是必要的,但我不知道如何实现。谁能帮我吗?

谢谢。

编辑:

我尝试过这样的触发器:

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

2 个答案:

答案 0 :(得分:1)

Oracle Objection Developer's documentation谈论防止悬挂裁判:

  

REF列可能受REFERENTIAL约束的约束,类似于对外键的规范。

不幸的是,文档没有提供有关此操作的实际示例。 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投掷。


触发器永远不是在常规表或对象表上强制外键约束的正确解决方案。因为

  1. 在FOR EACH ROW触发器中查询引用表效率低下,尤其是对于多行删除。外键已针对此任务进行了优化。
  2. 由于读取的提交隔离级别,因此该操作在多用户环境中不安全。当另一个用户在另一个会话中添加子行时,触发器将通过我们的删除操作。
  3. 外键约束是标准。偏离标准是不好的做法,因为这会使我们的代码难以维护。
  4. 在触发器中强制执行的规则未出现在数据字典中。这将使我们的同事感到困惑,防止对数据模型进行逆向工程,并将使优化器失去一些有用的信息以得出有效的执行计划。

答案 1 :(得分:0)

请改为使用更好的外键进行级联删除。

参照如下的t_movie或t_video表创建约束:

  ALTER TABLE child_table
  ADD CONSTRAINT fk_delete
  FOREIGN KEY (type)
  REFERENCES t_video (type)
  ON DELETE CASCADE;

从现在开始,对t_video的每次删除都会导致删除子表中的关联行。这就是你的目标。

如果您需要更多详细信息,请查看:https://www.techonthenet.com/oracle/foreign_keys/foreign_delete.php