oracle ddl 触发器:在删除之前创建备份 table

oracle ddl trigger: create backup table with before drop

我想使用 ddl 触发器(删除前)创建备份 table,但遇到了以下问题。

第一次丢弃时没关系:a_backup table 包含丢弃的数据 table。但是为什么我不能在这之后删除另一个 table?

ORA-01031: insufficient privileges



create table b (x number);

-- Table B created.

create table a (x number);

-- Table A created.

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

-- Table A_BACKUP created.

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

-- Trigger A_BACKUP_TR compiled


-- 1

drop table a;

-- Table A dropped.


-- 2

drop table b;

-- ORA-04045: errors during recompilation/revalidation of TRANEE.A_BACKUP_TR

-- ORA-01031: insufficient privileges

并且您不能在删除后删除任何 table,除非您再次运行创建或替换触发器脚本。 IF-THEN 部分有问题吗?当 table A 不存在时,IF 语句必须进入 NULL?

But why I cannot drop another table after this?

insert into a_backup select * from a; 

在触发器中,您明确引用了 table 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 所述,为了减少盲插入,您可以在触发器内创建 table:

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