简体   繁体   中英

Oracle SQL Check constraint between 2 tables

I got 2 tables, Persons and Relationships .

The Persons table got only 2 fields for now: ID and Age .

Relationships have 3 fields: Person_ID , Relative_ID and Relation

What I wanna do is simple: on insertion\\update to Relationships I want to check the following:

if Relation == 'child' and Persons[Person_ID].Age < Persons[Relative_ID].Age:
    Throw Exception

Thanks

You should create trigger.

Try this

CREATE OR REPLACE TRIGGER   my_trg
              BEFORE INSERT OR UPDATE ON Relationships
                 FOR EACH ROW
  declare
     function i_Age(id int) return int is
     li_res int;
     begin
       select p.Age
        into li_res 
        from Persons p 
        where p.ID= id 
         and rownum=1;
        return li_res;
    exception when no_data_found then
    return NULL; --or Throw Exception depend on your logic if some datas not found
     end;

     BEGIN
      IF INSERTING OR UPDATING THEN
          IF :NEW.Relation == 'child' and i_Age(:NEW.Person_ID) < i_Age(:NEW.Relative_ID)  then 
           NULL; --Throw Exception or your logic
          END IF;
      END IF;
   END;

Check constraints (using the phrase in its technical meaning), with the exception of referential constraints, can't encode constraints on data from two different tables.

One technique you can use is to create a materialized view and have a constraint on the view. For example:

create materialized view relationship_check_mv
build immediate
refresh fast on commit
as
  select 1 as flag
  from   persons       p1
         join
         relationships r  on p1.id = r.person_id
         join
         persons       p2 on p2.id = r.relative_id
  where  r.relationship = 'child'
    and  p1.age < p2.age

Of course, you will have to create materialized view logs first, etc. So, this materialized view will have one row for each INVALID relationship. Then create a constraint on the materialized view, for example for the condition flag = 0 . (Or, a bit simpler: change the MV to select null as flag from.... and make the column flag to be not null in the MV.)

Whenever an attempt to insert an invalid row into the relationships table is made, the materialized view would be updated with a new row; but the check constraint on the MV prevents that, so the entire transaction will fail.

CREATE OR REPLACE TRIGGER child_parent_age_tr BEFORE INSERT OR UPDATE ON RELATIONSHIPS FOR EACH ROW
    DECLARE 
        child_age NUMBER; 
        parent_age NUMBER;

    BEGIN
        SELECT AGE INTO child_age FROM PERSONS WHERE ID = :NEW.PERSON_ID;
        SELECT AGE INTO parent_age FROM PERSONS WHERE ID = :NEW.RELATIVE_ID;
        IF INSERTING OR UPDATING THEN
            IF :NEW.RELATION = 'child' AND child_age >= parent_age THEN
                RAISE INVALID_NUMBER;
            END IF;
        END IF;
    END;

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