oracle ddl触发器:使用之前删除创建备份表

时间:2018-07-06 15:59:04

标签: oracle plsql triggers ddl-trigger

我想用ddl触发器(在删除之前)创建一个备份表,并遇到以下问题。

第一次删除就可以了:a_backup表包含删除表的数据。但是为什么之后我不能再放另一个桌子呢?

  

ORA-01031:特权不足



create table b (x number);
  

-已创建表B。

create table a (x number);
  

-表A已创建。

create table a_backup as select * from a where 1 = 0;
  

-已创建表A_BACKUP。

create or replace trigger a_backup_tr
    before drop
    on database
begin
    IF ora_dict_obj_name <> 'A' then
    null;
    ELSIF ora_dict_obj_name = 'A'
    and ora_dict_obj_owner = 'TRANEE' then
    insert into a_backup
    select * from a;
    ELSE null;
    end if;
end;
/
  

-已编译触发器A_BACKUP_TR


-- 1

drop table a;
  

-表A已删除。


-- 2

drop table b;
  

-ORA-04045:重新编译/重新验证TRANEE.A_BACKUP_TR时出错

     

-ORA-01031:权限不足

并且您不能在删除之后删除任何表,除非您再次运行create或replace触发脚本。 IF-THEN部分有问题吗?当表A不存在时,IF语句必须变为NULL?

1 个答案:

答案 0 :(得分:5)

  

但是为什么我不能在此之后删除另一个表?

insert into a_backup select * from a; 

在触发器中,您明确引用表A,但该表当时不存在。

您可以使用动态SQL:

create or replace trigger a_backup_tr
    before drop
    on database
begin
    IF ora_dict_obj_name <> 'A' then
        null;
    ELSIF ora_dict_obj_name = 'A' and ora_dict_obj_owner = 'TRANEE' then
        EXECUTE IMMEDIATE 'insert into tranee.a_backup select * from tranee.a';
    ELSE null;
    end if;
end;
/

我个人不喜欢将触发器用于这种机制的想法。此外,如果将来模式发生漂移,则盲插入和SELECT *可能会失败。也许更好的方法是Flashback Drop (Recycle Bin)


编辑:

如@wolφi所述,为减少盲目插入,您可以在触发器内部创建表:

create or replace trigger a_backup_tr
    before drop
    on database
begin
    IF ora_dict_obj_name <> 'A' then
      null;
    ELSIF ora_dict_obj_name = 'A' and ora_dict_obj_owner = 'TRANEE' then
      --TODO: additional check if table already exists
      EXECUTE IMMEDIATE 'CREATE TABLE tranee.a_backup AS SELECT * FROM tranee.a';
    ELSE null;
    end if;
end;
/