-1

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

2 回答 2

1

好的,两点。首先,您的 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
于 2013-03-06T11:27:29.813 回答
0

我真的不喜欢以这种方式使用触发器和错误——数据完整性并不是触发器的真正用途。在我看来,这似乎是应用程序的一部分,应该包含在应用程序代码中,也许是在充当插入表的 API 的过程中。

于 2013-03-06T11:45:42.100 回答