使用触发器中断 Oracle 数据库删除和更新行

Posted

技术标签:

【中文标题】使用触发器中断 Oracle 数据库删除和更新行【英文标题】:Interrupt Oracle Database Delete and Update Row using Trigger 【发布时间】:2017-10-31 17:27:04 【问题描述】:

我有两个表(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`

【问题讨论】:

如果找到子记录,您不想引发异常或触发。 Oracle 将自动提升ORA-02292 Constraint violation - child records found 【参考方案1】:

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

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);

【讨论】:

【参考方案2】:

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

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);

【讨论】:

以上是关于使用触发器中断 Oracle 数据库删除和更新行的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE 和触发器(插入、更新、删除)

Oracle - ORA-01422:精确提取返回的行数超过了请求的行数

Oracle-触发器和程序包

Oracle中的触发器是请求的一部分吗?

oracle mybatis 批量更新 怎么获取影响行数

PL/SQL ORACLE:删除时触发更新