oracle ddl trigger:在删除之前创建备份表

dia*_*hol 1 oracle triggers plsql ddl-trigger

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

发生第一次丢弃时没关系:a_backup表包含丢弃表的数据.但为什么我不能放弃另一张桌子?

ORA-01031:权限不足



create table b (x number);
Run Code Online (Sandbox Code Playgroud)

- 表B已创建.

create table a (x number);
Run Code Online (Sandbox Code Playgroud)

- 表A已创建.

create table a_backup as select * from a where 1 = 0;
Run Code Online (Sandbox Code Playgroud)

- 表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;
/
Run Code Online (Sandbox Code Playgroud)

- 触发A_BACKUP_TR编译


-- 1

drop table a;
Run Code Online (Sandbox Code Playgroud)

- 表A下降.


-- 2

drop table b;
Run Code Online (Sandbox Code Playgroud)

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

- ORA-01031:权限不足

除了再次运行create或replace trigger脚本之外,您不能删除任何表.IF-THEN部分有问题吗?当表A不存在时,IF语句必须进入NULL状态?

Luk*_*zda 5

但为什么我不能放弃另一张桌子?

insert into a_backup select * from a; 
Run Code Online (Sandbox Code Playgroud)

在触发器中,您明确引用表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;
/
Run Code Online (Sandbox Code Playgroud)

就个人而言,我不喜欢使用触发器来实现这种机制.盲目插入也SELECT *可能会失败,如果将来架构漂移.也许更好的方法是Flashback Drop(回收站)


编辑:

正如@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;
/
Run Code Online (Sandbox Code Playgroud)