删除时触发以避免悬空引用
Trigger on delete to avoid dangling references
我在 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);
而且我还有关联的 tables
CREATE TABLE movies OF t_movie
CREATE TABLE videos OF t_video
如果我从 table 电影中删除一个元组,我将在另一个 table 中有一些元组引用不再存在的对象。我怎样才能避免这种情况?我认为触发器是必要的,但我不知道如何实现它。谁能帮帮我?
谢谢。
编辑:
我试过这样的触发器:
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
改为触发,使用更好的外键进行级联删除。
参考 t_movie 或 t_video table 创建约束,如下所示:
ALTER TABLE child_table
ADD CONSTRAINT fk_delete
FOREIGN KEY (type)
REFERENCES t_video (type)
ON DELETE CASCADE;
从现在开始,t_video 上的每次删除都会导致删除子 table 中的关联行。这就是你的目标。
如果您需要更多详细信息,请查看:https://www.techonthenet.com/oracle/foreign_keys/foreign_delete.php
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
。
触发器永远不是对常规或对象 table 强制执行外键约束的正确解决方案。因为
- 在 FOR EACH ROW 触发器中查询引用 table 效率低下,尤其是对于多行删除。外键针对此任务进行了优化。
- 由于读提交隔离级别,该操作在多用户环境中不安全。当另一个用户在不同的会话中添加子行时,触发器将传递我们的删除。
- 外键约束是标准的。偏离标准是不好的做法,因为它使我们的代码更难维护。
- 触发器中强制执行的规则不会出现在数据字典中。这将使我们的同事感到困惑,阻止数据模型的逆向工程,并使优化器无法获得一些有用的信息来得出有效的执行计划。
我在 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);
而且我还有关联的 tables
CREATE TABLE movies OF t_movie
CREATE TABLE videos OF t_video
如果我从 table 电影中删除一个元组,我将在另一个 table 中有一些元组引用不再存在的对象。我怎样才能避免这种情况?我认为触发器是必要的,但我不知道如何实现它。谁能帮帮我?
谢谢。
编辑:
我试过这样的触发器:
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
改为触发,使用更好的外键进行级联删除。
参考 t_movie 或 t_video table 创建约束,如下所示:
ALTER TABLE child_table
ADD CONSTRAINT fk_delete
FOREIGN KEY (type)
REFERENCES t_video (type)
ON DELETE CASCADE;
从现在开始,t_video 上的每次删除都会导致删除子 table 中的关联行。这就是你的目标。
如果您需要更多详细信息,请查看:https://www.techonthenet.com/oracle/foreign_keys/foreign_delete.php
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
。
触发器永远不是对常规或对象 table 强制执行外键约束的正确解决方案。因为
- 在 FOR EACH ROW 触发器中查询引用 table 效率低下,尤其是对于多行删除。外键针对此任务进行了优化。
- 由于读提交隔离级别,该操作在多用户环境中不安全。当另一个用户在不同的会话中添加子行时,触发器将传递我们的删除。
- 外键约束是标准的。偏离标准是不好的做法,因为它使我们的代码更难维护。
- 触发器中强制执行的规则不会出现在数据字典中。这将使我们的同事感到困惑,阻止数据模型的逆向工程,并使优化器无法获得一些有用的信息来得出有效的执行计划。