比较来自不同表的两个数据时如何使用触发器?

时间:2014-03-01 14:30:55

标签: sql database oracle plsql triggers

CONSTRAINT (Movie.Date – person.DateOfBirth >= Movie.MinAge)

我正在尝试使用触发器进行此约束,我不确定在比较来自不同表的不同数据时如何使用触发器。

2 个答案:

答案 0 :(得分:0)

像这样......我没有测试它!!

CREATE OR REPLACE TRIGGER check_movie_parent_rating
BEFORE INSERT OR UPDATE OF DateOfBirth ON Person
REFERENCING NEW AS n                 
FOR EACH ROW
DECLARE
   v_allowed VARCHAR2(1);
BEGIN
   BEGIN
        SELECT CASE WHEN (Movie.Date - person.DateOfBirth  >= Movie.MinAge)
                    THEN 'Y'
                    ELSE 'N'
                END As Allowed
        INTO v_allowed 
        FROM Movie , Person
        WHERE Movie.id = :n.movieId
        AND Person.movieId = Movie.id
        AND Person.id = :n.id;
   EXCEPTION
   WHEN NO_DATA_FOUND THEN
      v_allowed := NULL;
   END;

   IF v_allowed IS NULL THEN
      Raise_application_error(-20202, 'Movie Detail not available in parent');
   ELSIF v_allowed = 'N' THEN
      Raise_application_error(-20201, 'Movie Restricted for User');
   END IF;
END;
/

答案 1 :(得分:0)

这是一个解决方案,可以避免当您从针对同一个表定义的行级触发器中的表中选择时出现的变异表错误。

每当更改任何相关表时,都应检查约束。

理想情况下,触发器内还应该有序列化锁,以确保并发执行的事务不会以破坏约束的方式更改数据。这可以通过使用提供的DBMS_LOCK包中的模块来实现。

CREATE OR REPLACE TRIGGER Movie_Check_Age
AFTER INSERT OR UPDATE OF <Join_Columns>, Date, MinAge ON Movie
FOR EACH ROW
DECLARE
  CURSOR csrPersons
  IS
    SELECT NULL
    FROM Person p
    WHERE p.<Join_Columns> = :new.<Join_Columns>
    AND   (Months_Between(:new.Date, p.DateOfBirth) / 12) < :new.MinAge;
  rPerson csrPersons%ROWTYPE;
BEGIN
  OPEN csrPersons;
  FETCH csrPersons INTO rPerson;
  IF csrPersons%FOUND THEN
    CLOSE csrPersons;
    Raise_Application_Error(-20001, 'Person too young to see movie');
  ELSE
    CLOSE csrPersons;
  END IF;
END;
/

CREATE OR REPLACE TRIGGER Person_Check_Age
AFTER INSERT OR UPDATE OF <Join_Columns>, DateOfBirth ON Person
FOR EACH ROW
DECLARE
  CURSOR csrMovies
  IS
    SELECT NULL
    FROM Movie m
    WHERE m.<Join_Columns> = :new.<Join_Columns>
    WHERE (Months_Between(m.Date, :new.DateOfBirth) / 12) < m.MinAge;
  rMovie csrMovies%ROWTYPE;
BEGIN
  OPEN csrMovies;
  FETCH csrMovies INTO rMovie;
  IF csrMovies%FOUND THEN
    CLOSE csrMovies;
    Raise_Application_Error(-20001, 'Person too young to see movie');
  ELSE
    CLOSE csrMovies;
  END IF;
END;
/