使用Trigger中断Oracle数据库删除和更新行

时间:2017-10-31 17:27:04

标签: database oracle plsql triggers

我有两个表(T1和T2),T2.T1_ID引用T1.ID.我正在尝试使用触发器对T1中的行删除操作进行操作,这样如果T2中没有对T1行的引用,则删除T1行。否则,它只是在T1行的HIDDEN列上设置一个标志值。我已经尝试通过检查T2匹配引用来做到这一点,如果是这样,我引发一个异常取消删除并尝试设置标志,但它似乎不起作用。编译触发器时,我收到错误

  

“ORA-04084:无法更改此触发类型的新值”

我猜这与我在删除操作期间尝试更改数据这一事实有关。我尝试过类似问题的“删除后”触发器。这是我想要做的一个简单的例子:

create table "T1" (
  "ID" number not null enable,
  "HIDDEN" number,
  constraint "T1_PK" primary key ("ID")
);

create table "T2" (
  "T1_ID" number not null enable,
  "VAL" number,
  constraint "T2_FK1" foreign key ("T1_ID") references "T1" ("ID") enable
);

create or replace trigger "BD_T1"
  before delete on "T1"
  for each row
declare
  cnt NUMBER;
  records_found EXCEPTION;    
begin   
  select count(*) into cnt from T2 where T1_ID = :OLD."ID";
  if cnt > 0 then
    RAISE records_found;
  end if;
exception
  when records_found then
    :NEW."HIDDEN" := 1; -- set hidden flag and abort delete operation
end;

insert into T1 ("ID") values (1);
insert into T1 ("ID") values (2);

insert into T2 ("T1_ID", "VAL") values (1, 100);
insert into T2 ("T1_ID", "VAL") values (1, 200);

select * from T1;
delete from T1 where ID = 2; --no references so row deleted
select * from T2;
delete from T1 where ID = 1; -- references found so abort delete and set     hidden flag`

2 个答案:

答案 0 :(得分:1)

基本上,您的触发器正在尝试将DELETE语句更改为UPDATE语句。你不能做这个!但是,您可以通过完全消除触发器来完成所需的操作,并使用带有delete选项的MERGE语句替换DELETE语句。尝试:

merge into t1
  using (select 1 t1id from dual
         union all 
         select 2 t1id from dual) t
  on (t1.id = t.t1id) 
  when matched then 
      update set t1.hidden = 1 
      delete where not exists 
             (select null from t2 where t2.t1_id = t1id);

答案 1 :(得分:0)

基本上,您的触发器正在尝试将DELETE语句更改为UPDATE语句。你不能做这个!但是,您可以通过完全消除触发器来完成所需的操作,并使用带有delete选项的MERGE语句替换DELETE语句。尝试:

merge into t1
  using (select 1 t1id from dual
         union all 
         select 2 t1id from dual) t
  on (t1.id = t.t1id) 
  when matched then 
      update set t1.hidden = 1 
      delete where not exists 
             (select null from t2 where t2.t1_id = t1id);