简体   繁体   中英

Trigger on delete to avoid dangling references

I have a problem with the implementation of some triggers in Oracle.

I have two types "t_movie" and "t_video" defined as

CREATE TYPE t_movie AS OBJECT( 
name VARCHAR(20),
year INTEGER);

And

CREATE TYPE t_video AS OBJECT( 
type CHAR,
movie REF t_movie);

And I have also the associated tables

CREATE TABLE movies OF t_movie


CREATE TABLE videos OF t_video

If I delete a tuple from the table movies I will have some tuples in the other table with references to object that doesn't exist anymore. How can I avoid this? I thought that a trigger is necessary but I have no idea of how to implement it. Can anyone help me?

Thanks.

Edit:

I tried a trigger like this:

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;

But, as expected, I get the error

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

The Oracle Objection Developer's documentation talks of preventing dangling refs:

A REF column may be constrained with a REFERENTIAL constraint similar to the specification for foreign keys.

Unfortunately the documentation doesn't provide an actual example of how do to this. The formatting of REFERENTIAL suggests that it is a keyword but that turns out to be a red herring.

The solution really is to define an actual foreign key but using object references instead. So, taking the code you posted, change the definition of videos to this:

CREATE TYPE t_video AS OBJECT( 
    type CHAR,
    movie REF t_movie
);
/
CREATE TABLE videos OF t_video (
    foreign key (movie) references movies
)
/

Now if you attempt to delete a movie which is referenced by a video Oracle will hurl ORA-02292: integrity constraint .


Triggers are never the correct solution to enforcing foreign key constraints on regular or object tables. Because

  1. Querying the referencing table in a FOR EACH ROW trigger is inefficient, especially for multi-row deletions. Foreign keys are optimised for this task.
  2. The operation is unsafe in a multi-user environment, due to read committed isolation level. The trigger will pass our deletion while another user is adding a child row in a different session.
  3. Foreign key constraints are the standard. Deviating from the standard is bad practice, because it makes our code harder to maintain.
  4. Rules enforced in triggers don't appear in the data dictionary. This will confuse our co-workers, prevent reverse engineering of the data model and will deprive the optimiser of some useful information for deriving efficient execution plans.

Instead trigger, use better foreign key with cascade delete.

Create constraint with reference to t_movie or t_video table like below:

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

From now, every delete on t_video causes deleting associate rows in child table. And this is your goal.

If you need more details, please review: https://www.techonthenet.com/oracle/foreign_keys/foreign_delete.php

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM