我在table1上插入触发器之前。如果不允许某些数据(ID),则会引发应用程序错误。
但是,当我使用时,insert into table1 select id from table2 where id in (1,2,3)
如果不允许ID为'3',则其他ID(1和2)也不会被插入。
我怎样才能克服这一点?触发器代码类似于:
CREATE OR REPLACE TRIGGER t1_before_insert BEFORE INSERT
ON table1
FOR EACH ROW
DECLARE
xx number(20);
BEGIN
select id into xx from blocked_id where id=:new.id;
if :new.id=xx then raise_application_error(-20001, '--');
end if;
END;
答案 0 :(得分:1)
好的,两点。首先,你在SELECT INTO ...中冒着NO_DATA_FOUND异常的风险,提出这个异常会终止你的整个插入。其次,你提出了一个例外,这将阻止你的整个插入。
您需要忽略阻止表中的ID,而不是引发异常。要遵循您的原始想法,一种方法是利用NO_DATA_FOUND异常仅在未找到任何内容时插入。我在您的桌子上创建了一个视图,并在此处定义了INSTEAD OF trigger。
我不会使用这种方法(见下文)
如果我们设置测试环境:
SQL> create table tmp_test ( id number );
Table created.
SQL> create table tmp_blocked ( id number );
Table created.
SQL> insert into tmp_blocked values (3);
1 row created.
然后您可以使用以下内容:
SQL> create or replace view v_tmp_test as select * from tmp_test;
View created.
SQL> create or replace trigger tr_test
2 instead of insert on v_tmp_test
3 for each row
4
5 declare
6
7 l_id tmp_test.id%type;
8
9 begin
10
11 select id into l_id
12 from tmp_blocked
13 where id = :new.id;
14
15 exception when no_data_found then
16 insert into tmp_test values (:new.id);
17 end;
18 /
Trigger created.
SQL> show error
No errors.
SQL> insert into v_tmp_test
2 select level
3 from dual
4 connect by level <= 3;
3 rows created.
SQL> select * from tmp_test;
ID
----------
1
2
正如我所说,我不会使用触发器;更有效的方法是使用MERGE。使用与上面相同的设置。
SQL> merge into tmp_test o
2 using ( select a.id
3 from ( select level as id
4 from dual
5 connect by level <= 3 ) a
6 left outer join tmp_blocked b
7 on a.id = b.id
8 where b.id is null
9 ) n
10 on ( o.id = n.id )
11 when not matched then
12 insert values (n.id);
2 rows merged.
SQL>
SQL> select * from tmp_test;
ID
----------
1
2
更简单的替代方法是使用MINUS
insert into tmp_test
select level
from dual
connect by level <= 3
minus
select id
from tmp_banned
答案 1 :(得分:0)
我真的不喜欢以这种方式使用触发器和错误 - 数据完整性并不是触发器的真正原因。在我看来,这应该是应用程序代码中应该包含的应用程序的一部分,可能是作为插入表中的API的过程。