我想用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?
答案 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;
/