Oracle SQL - 创建访问多个表的触发器

标签 oracle join plsql database-trigger

我有三个表:

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 之前创建一个触发器,以防止家庭成员照顾自己的 child 。因此,如果在 table_babysit 中,family_babysitter_id 与 child 的 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;

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

最佳答案

无论是触发器、标准过程中的语句,还是只是使用 JOIN 的独立查询,它都必须遵循以下形式 从 table1 选择 ... [进入 ...] 根据 join_condition JOIN table2 ... 触发器和过程语句需要 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

我确信还有其他 JOINS 可以实现您的愿望。我现在想不出一个。但也许最容易理解的是使用 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;

关于Oracle SQL - 创建访问多个表的触发器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47501001/

相关文章:

sql - 在触发器中使用 DBMS_PIPE.PACK_MESSAGE 和 DBMS_PIPE.SEND_MESSAGE

database - Oracle 11g - 通过 user_id 跨池连接共享 Sys_Context 值

sql - 查找包含特定表或列的所有 View

sql - Access 加入 TRANSFORM/PIVOT 查询

php - Yii 多对多,联结表对象图

sql - 使用 v ('APP_USER' ) 作为 Oracle Apex 中列的默认值

java - 存储过程调用期间使用 CallableStatement 的 SQL 语句无效

sql - C 代码中 OCINumberFromText 中 'TEXT' 的格式

c# - 错误 System.Data.OracleClient 在安装设置时需要 Oracle 客户端软件版本 8.1.7 或更高版本

php - 请协助我建立这个查询