【问题标题】:oracle ddl trigger: create backup table with before droporacle ddl 触发器:使用删除前创建备份表
【发布时间】:2018-12-15 06:38:45
【问题描述】:

我想用ddl触发器(drop前)创建一个备份表,遇到了以下问题。

发生第一次删除时没关系: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: 权限不足

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

【问题讨论】:

  • 刚刚注意到您在问题中开发的功能与 Oracle 的 recyclebin 功能非常相似。

标签: oracle plsql triggers ddl-trigger


【解决方案1】:

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

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

【讨论】:

  • 是否需要在 ON DATABASE 触发器中限定 a_backup 的架构?
  • @wolφi 它将按原样工作。但明确限定名称是个好主意。
  • 好的,谢谢! @diaphol:我同意 Lukasz 的观点,即在触发器中备份可能不是一个好主意。如果有的话,我会在触发器主体中使用CREATE TABLE tranee.a_backup AS SELECT * FROM tranee.a,而不是INSERT。它更快(没有撤消)、更安全(列没有问题)和更简洁(代码在一个地方)。
  • 感谢编辑,非常友好! 'RENAME' 是否也会起作用,还是会弄乱DROP 声明?而且,想想看,这正是RECYCLEBIN 所做的,不是吗?
  • @wolφi 是的,该技术称为Flashback Drop (Recycle Bin)。至于重命名不会触发drop。
猜你喜欢
  • 2020-10-12
  • 2021-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-19
  • 2013-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多