如何通过oracle触发器限制插入记录

时间:2015-03-07 17:50:28

标签: plsql

我想限制插入表格的记录,我在创建触发器之前的插入位置。 我有一个场景

Table A
  id number
  id1 number
Table B
  id number
Table c
  id number
Table D
  id number
  id1 number

我的代码:

create or replace trigger trg_a --trigger name
  before insert on a
  for each row
    declare
      v_id b.id%type;
      v_id1 c.id%type;
    pragma autonomous_transaction;  
    begin
      select id into v_id from b where id=:NEW.id;
      select id into v_id1 from c where id=:NEW.id; 
      if(:NEW.id=v_id or :NEW.id=v_id1) then
        insert into d
          (id,id1,name)
        values(:NEW.id,:NEW.id1,:NEW.name);
      end if;
      delete from a where id =v_id or id 1=v_id1 ; --matched id
      commit;
    end;  --end statement

插入匹配记录与查找表,即bc和并行y也插入表a。此记录插入需要限制,因此我保留了删除语句,但它不起作用。

2 个答案:

答案 0 :(得分:0)

您正尝试在单独的交易中执行此操作。我没有看到原因,这也导致您的代码无法正常工作。

可能你没有在每次插入后提交,所以当在触发器体内启动新事务时,它没有看到表A中的任何记录被删除。

我遗漏了pragma autonomous_transaction和commit;现在它按照您的预期从表中删除记录。 (请注意,我对您的代码进行了一些更改,因为它不能编译,因为NAME列不存在且ID为1)

create or replace trigger trg_a --trigger name
before insert on a
for each row
declare
  v_id b.id%type;
  v_id1 c.id%type;
--pragma autonomous_transaction;  
begin
  select id into v_id from b where id=:NEW.id;
  select id into v_id1 from c where id=:NEW.id; 
  if(:NEW.id=v_id or :NEW.id=v_id1) then
    insert into d
      (id,id1)
    values(:NEW.id,:NEW.id1);
  end if;
  delete from a where id =v_id or id1=v_id1 ; --matched id
  --commit;
end;  
/

因此要么在每次插入后提交,要么省略自治事务。

更新: 现在你说清楚了,你根本不想插入表格a。由于INSTEAD OF触发器仅适用于视图,我担心只有这样才能实现此操作才会导致运行时异常,因此插入到A中将不会成功,但INSERT到表D中会成功。看看这个,当将varchar值分配给数字列时,它会导致插入PL / SQL数值或值错误

create or replace trigger trg_a --trigger name
  before insert on a
  for each row
   declare
  v_id b.id%type;
  v_id1 c.id%type;
 pragma autonomous_transaction;  
  begin
  select id into v_id from b where id=:NEW.id;
  select id into v_id1 from c where id=:NEW.id; 
  if(:NEW.id=v_id or :NEW.id=v_id1) then
    insert into d
      (id,id1)
    values(:NEW.id,:NEW.id1);
  end if;
  delete from a where id =v_id or id1=v_id1 ; --matched id
  commit;
   :NEW.id:=null;
   :NEW.id1:='a';
end;  
 /

答案 1 :(得分:0)

如果您有11g或更高版本,您可能需要查看使用复合触发器。

Create Or Replace Trigger Trg_A
For Insert On A
Compound Trigger
    Type Id_T Is Table Of A.Id%type Index By Simple_Integer;
    Id_List   Id_T;
    Id_ndx    simple_integer := 0;
    Id_Count  Integer;

    After Each Row Is Begin
        -- If the same id is in Table B or Table C
        Select Count(*) Into Id_Count From B Where Id = :New.ID;
        If Id_Count = 0 Then
            -- Only check C if nothing in B
            Select Count(*) Into Id_Count From C Where Id = :New.ID;
        End If;
        If Id_Count > 0 Then
            -- If already in B or C, log to D
            Insert Into D( Id, Id1, Name )
            Values( :New.ID, :New.ID, :New.Name);
            -- Then save for later deletion from A
            Id_ndx  := Id_ndx + 1;
            Id_List( Id_ndx ) := :New.Id;
        End If;
    End After Each Row;
    After Statement Is Begin
        Forall Idx In 1 .. Id_ndx
            -- Delete saved IDs (if any)
            Delete From A Where Id = Id_List( Idx );
        Id_List.Delete();
        Id_ndx := 0;
    End After Statement;
End;

问题是在复合触发器中使用自治事务编译指示很棘手。它甚至可能是不可能的,我只是没有任何经验。

但是,有几个人在视图中提到“而不是”触发器。当我设计数据库时,几乎所有DML都通过视图,其中许多视图都存在,没有其他原因。很多时候,表将具有多个视图,因此无论数据如何被访问,都可以进行DML。我无法开始告诉你这解决了多少问题。因此,您可能需要认真考虑该选项。