好的,两点。首先,您的 SELECT INTO ... 冒着NO_DATA_FOUND异常的风险,引发此异常将杀死您的整个插入。其次,您提出了一个异常,这将停止您的整个插入。
您需要忽略阻止表中的那些 ID,而不是引发异常。按照您最初的想法,一种方法是利用 NO_DATA_FOUND 异常仅在未找到任何内容时插入。我在您的表上创建了一个视图,并在此定义了一个INSTEAD OF 触发器。
我不会使用这种方法(见下文)
如果我们设置一个测试环境:
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