【问题标题】:Oracle SQL - Creating trigger that accesses multiple tablesOracle SQL - 创建访问多个表的触发器
【发布时间】:2018-05-10 02:31:53
【问题描述】:

我有三张桌子:

table_family(
id CHAR(4) PRIMARY KEY,
name VARCHAR(30)
)

table_child(
id CHAR(4) PRIMARY KEY,
name VARCHAR(30),
family_parents_id CHAR(4) REFERENCES table_family(id)
)

table_babysit(
family_babysitter_id CHAR(4) REFERENCES table_family(id),
child_babysittee_id CHAR(4) REFERENCES table_child(id),
hours INTEGER
)

我试图在插入 table_babysit 之前创建一个触发器,以防止家庭成员照看自己的孩子。因此,如果在 table_babysit 中,family_babysitter_id 与孩子的 family_parents_id 匹配相同的家庭 id,那将是非法的。

CREATE TRIGGER check_illegal_babysit
BEFORE INSERT
ON table_babysit
FOR EACH ROW
BEGIN
JOIN table_family ON table_family.id = family_babysitter_id
JOIN table_child ON table_child.id = child_babysittee_id
IF (table_family.id = table_child.family_parents_id) THEN
RAISE_APPLICATION_ERROR(-20000,'Family cannot babysit their own children');
END IF;
END;

我是编写触发器的新手,我似乎无法在触发器中加入多个表。创建此触发器的正确​​方法是什么?

【问题讨论】:

    标签: oracle join plsql database-trigger


    【解决方案1】:

    无论是触发器、标准过程中的语句,还是只是使用 JOIN 的独立查询,它都必须遵循以下形式 Select ... [into ...] from table1 JOIN table2 on join_condition ... 其中触发器和程序语句需要 INTO 短语。

    在他的情况下,您可以使用 CTE 来创建 table1。但是,这里有一个复杂之处,即连接所需的条件实际上是触发器试图阻止的条件,但可以通过反转逻辑并选择您不想要的条件来使其工作:

    -- define trigger (with join)
    create or replace trigger check_illegal_babysit
    before insert
    on table_babysit
    for each row
    declare 
       x varchar2(1);
    
    begin
         with s as
              (select :new.family_babysitter_id sitter
                    , :new.child_babysittee_id  sittee
                 from dual 
              )       
         select null
           into x
           from s 
                 left outer join table_family on(table_family.id = sitter)
                 left outer join table_child  on(table_child.id  = sittee)
           where table_family.id = table_child.family_parents_id;             
    
           raise_application_error(-20000,'Family cannot babysit their own children');
     exception 
       when no_data_found then null;
    end;
    
    --- Create test Family and Child rows
    insert into table_family (id, name) values('Fam1','Family1');
    insert into table_family (id, name) values('Fam2','Family2');
    insert into table_family (id, name) values('Fam3','Family3');
    
    insert into table_child( id,name,family_parents_id) values('c1f1', 'Child1 of Family1', 'Fam1');
    insert into table_child( id,name,family_parents_id) values('c2f1', 'Child2 of Family1', 'Fam1');
    insert into table_child( id,name,family_parents_id) values('c3f1', 'Child3 of Family1', 'Fam1');
    insert into table_child( id,name,family_parents_id) values('c1f2', 'Child1 of Family2', 'Fam2');
    insert into table_child( id,name,family_parents_id) values('c2f2', 'Child2 of Family2', 'Fam2');    
    
    -- Insert into babysit table to test trigger
    insert into table_babysit(family_babysitter_id, child_babysittee_id)  values( 'Fam2', 'c1f1') ; -- valid
    insert into table_babysit(family_babysitter_id, child_babysittee_id)  values( 'Fam3', 'c2f1') ; -- valid
    insert into table_babysit(family_babysitter_id, child_babysittee_id)  values( 'Fam1', 'c3f1') ; -- invalid
    

    我确信还有其他 JOIN 可以实现您的愿望。我现在想不出一个。但也许最容易理解的是使用 2 个简单的直接选择。所以不妨试试:

    create or replace trigger check_illegal_babysit
        before insert
        on table_babysit
        for each row
    declare 
           family_id_l  table_family.id%type;
           parents_id_l table_child.family_parents_id%type;
    begin 
    
         select table_family.id 
           into family_id_l
           from table_family
          where id = :new.family_babysitter_id;
    
         select family_parents_id 
           into parents_id_l
           from table_child
          where id = :new.child_babysittee_id;
    
         if (family_id_l =  parents_id_l) then
            raise_application_error(-20000,'Family cannot babysit their own children');
         end if;
    end;
    

    【讨论】:

      猜你喜欢
      • 2015-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      • 2018-12-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多