插入禁止列表中的所有记录

时间:2013-03-06 08:53:58

标签: oracle triggers insert

我在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;

2 个答案:

答案 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的过程。