sql - 删除时触发以避免悬空引用

标签 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

如果我从表 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 a REFERENTIAL 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


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

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

关于sql - 删除时触发以避免悬空引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54384101/

相关文章:

mysql - 在sql嵌套查询中比较同一个表

sql - 在 PostgreSQL 中存储和查询区间树

sql - PL/SQL - dbms 输出立即执行的结果

oracle - 没有映射的Doctrine 2.0 native 查询

php - 在 ORACLE 数据库警告和 fatal error 中保存 XML 数据时出错

mysql - 如何从mysql表中获取最后一条记录和倒数第二条记录

c# - GridView ASP.NET C# 中的丑陋时间格式

mysql - MySQL存储引擎的日志表

mysql - 将数据库导入到 ms sql server

php - 在我的 php 项目中哪个更好? 1 个带有多个空字段的表 1 个带有多个空字段的表?