触发器(ORA-39083、ORA-00942)的 Oracle IMPDP REMAP_SCHEMA 问题是不是有很好的解决方法?

Posted

技术标签:

【中文标题】触发器(ORA-39083、ORA-00942)的 Oracle IMPDP REMAP_SCHEMA 问题是不是有很好的解决方法?【英文标题】:Is there a good workaround to the Oracle IMPDP REMAP_SCHEMA issue with triggers (ORA-39083, ORA-00942)?触发器(ORA-39083、ORA-00942)的 Oracle IMPDP REMAP_SCHEMA 问题是否有很好的解决方法? 【发布时间】:2011-01-09 10:46:23 【问题描述】:

可以使用 Oracle 数据泵导入工具 (IMPDP.EXE) 使用 REMAP_SCHEMA 选项将一个模式导入另一个模式。但是,存在一个问题,即未正确重新映射触发器。这导致根本没有创建触发器,并出现如下错误:

ORA-39083: Object type TRIGGER failed to create with error: ORA-00942: table or view does not exist Failing sql is: CREATE TRIGGER "**NEW_SCHEMA**"."METER_ALARMS_BI"   BEFORE INSERT ON
**OLD_SCHEMA**.METER_ALARMS ...

这是因为创建 SQL 仍然引用 OLD_SCHEMA。它确实在 Oracle 文档中说:

映射可能不是 100% 完整,因为有一定的 架构引用 Import 不是 能够找到。例如, 导入将找不到架构引用 嵌入体内 类型、视图的定义, 程序和包。

恕我直言,这是甲骨文的一种逃避,但这是另一个讨论!

根据 Oracle Metalink note 750783.1,解决方法是:

    创建一个 SQLFILE 以包含相关的 DDL 命令:
      impdp system/****** directory=test_dp
      DUMPFILE=export_schemas.dmp
     remap_schema=u1:u2 sqlfile=script.sql
    从写入的 SQLFILE 中提取受影响的 DDL 并更正 架构参考。然后手动执行命令。

这不是一个好方法,尤其是当您有许多失败的对象并且想要自动化组合多个模式以进行数据库现场升级的过程时。

有没有人找到更好的方法来做到这一点?如果要在现场使用,我需要一个必须 100% 可靠的解决方案。我可以解析生成的 SQL 文件,但可以 100% 正确吗?有没有办法拦截由 IMPDP 执行的 CREATE SQL 语句并在导入时即时纠正它?可以直接修补 DMP 文件吗?

【问题讨论】:

我开始写这个作为答案,但实际上更多的是评论 - 我想不出有什么好的理由将模式的名称作为对象限定符包含在模式拥有的另一个对象中.我不清楚您对正在升级的数据库有什么控制权,但我会投票支持一次性清理这些引用以从源头上消除问题。在 DataPump 之前 (exp/imp) 的日子里,我直接修改了 .dmp 文件几次没有问题,但没有查看更新的格式。显然,如果您这样做,就 Oracle 而言,您只能靠自己。 注意点:我们正在处理一些将被清理的遗留对象,但即使是无所有者模式,IMPDP 的 REMAP_SCHEMA 仍然无法与触发器一起正常工作。是的,我还直接“修补”了 DMP 文件以重新映射架构,但是我发现使用 EXP 而不是 EXPDP 创建的 DMP 文件时问题较少。 按照 Oracle 的建议,使用 SQLFILE 选项生成由 IMPDP 执行的 SQL 在使用 SQL*Plus 运行时也会出现问题: - 存储过程 cmets 中的随机 cr/lf,给出“ORA-00933: SQL 命令未正确结束”等 - 生成的 SQL 对于视图来说太长,给出“SP2-0027:输入太长(> 2499 个字符)- 忽略行”。 确实应该有适当的解决办法 【参考方案1】:

我认为这取决于架构名称是否可以作为非架构名称的一部分出现在您的代码中。例如,您的变量名称是否包含与架构名称相同的字符。如果不是,那么我认为编写一个编辑生成的触发器创建脚本的过程用新的模式替换旧模式并不难。也许您可以使用数据泵导出/导入没有文本代码的对象类型(不是触发器、包、过程、函数等),然后转储代码对象的 SQL 并用新模式替换旧模式.

如果旧的架构名称出现在您不想替换的地方,那将更难做到。您可能会提取代码对象并尝试创建它们并收集所有错误。然后获取失败的对象的名称,并尝试根据错误将 oldschema.objectname 替换为 newschema.objectname 并重新运行。

假设没有像 oldschema 这样的字符串,您可以如何在触发器文本中编辑架构的示例。你不想替换的:

Example

SQL> 
SQL> set define off
SQL> 
SQL> drop table test1.tab1;

Table dropped.

SQL> drop table test1.tab2;

Table dropped.

SQL> 
SQL> create table test1.tab1
  2  (
  3     col1 number,
  4     col2 number
  5  );

Table created.

SQL> 
SQL> create table test1.tab2
  2  (
  3     col1 number,
  4     col2 number
  5  );

Table created.

SQL> 
SQL> create or replace trigger test1.trg1
  2  before insert or update on test1.tab1
  3  for each row
  4  begin
  5    :new.col2 := :new.col1*2;
  6  end;
  7  /

Trigger created.

SQL> 
SQL> create or replace trigger test1.trg2
  2  before insert or update on test1.tab2
  3  for each row
  4  begin
  5    :new.col2 := :new.col1*2;
  6  end;
  7  /

Trigger created.

SQL> 
SQL> drop table clobout;

Table dropped.

SQL> 
SQL> create table clobout (doc clob);

Table created.

SQL> 
SQL> declare
  2  h NUMBER; --handle returned by OPEN
  3  th NUMBER; -- handle returned by ADD_TRANSFORM
  4  doc CLOB;
  5  BEGIN
  6  
  7  -- Specify the object type.
  8  h := DBMS_METADATA.OPEN('TRIGGER');
  9  
 10  -- Use filters to specify the particular object desired.
 11  DBMS_METADATA.SET_FILTER(h,'SCHEMA','TEST1');
 12  
 13  -- Request that the schema name be modified.
 14  th := DBMS_METADATA.ADD_TRANSFORM(h,'MODIFY');
 15  DBMS_METADATA.SET_REMAP_PARAM(th,'REMAP_SCHEMA','TEST1','TEST2');
 16  
 17  -- Request that the metadata be transformed into creation DDL.
 18  th := DBMS_METADATA.ADD_TRANSFORM(h,'DDL');
 19  
 20  dbms_metadata.set_transform_param(th,'SQLTERMINATOR',true);
 21  
 22  -- Fetch the triggers.
 23  
 24  LOOP
 25    doc := DBMS_METADATA.FETCH_CLOB(h);
 26    EXIT WHEN (doc is null);
 27    insert into clobout values (doc);
 28    commit;
 29  END LOOP;
 30  
 31  -- Release resources.
 32  DBMS_METADATA.CLOSE(h);
 33  END;
 34  /

PL/SQL procedure successfully completed.

SQL> 
SQL> -- update schema name in triggers
SQL> 
SQL> update clobout set doc=replace(doc,'test1.','test2.');

2 rows updated.

SQL> 
SQL> commit;

Commit complete.

SQL> 
SQL> select doc from clobout;

  CREATE OR REPLACE EDITIONABLE TRIGGER "TEST2"."TRG1"
before insert or update on test2.tab1
for each row
begin
  :new.col2 := :new.col1*2;
end;
/
ALTER TRIGGER "TEST2"."TRG1" ENABLE;


  CREATE OR REPLACE EDITIONABLE TRIGGER "TEST2"."TRG2"
before insert or update on test2.tab2
for each row
begin
  :new.col2 := :new.col1*2;
end;
/
ALTER TRIGGER "TEST2"."TRG2" ENABLE;


SQL> 
SQL> spool off

【讨论】:

【参考方案2】:

您可以查看 DBMS_METADATA

有一个REMAP_SCHEMA 选项。不确定它是否会比 DATAPUMP 更好(我怀疑 DATAPUMP 会在幕后使用 DBMS_METADATA)。但是对输出进行“后处理”会更容易。

【讨论】:

我已经检查过了,即使在 11gR2 中,DBMS_METADATA REMAP_SCHEMA 转换只会影响拥有该对象的架构,而不会显式指定代码/对象定义中引用的对象架构(除非列具有具有显式模式名称的用户定义类型,当它被转换时)。

以上是关于触发器(ORA-39083、ORA-00942)的 Oracle IMPDP REMAP_SCHEMA 问题是不是有很好的解决方法?的主要内容,如果未能解决你的问题,请参考以下文章

数据泵导出导入物化视图

SQLDeveloper 触发器错误报告 - ORA-00942:表或视图不存在

SQLDeveloper触发器错误报告 - ORA-00942:表或视图不存在

ORA-00942: table or view does not exist

impdp时报错ORA-39083&ORA-01917

dataPump Import Fails With Errors ORA-39083 ORA-1858 or ORA-39083 ORA-1843 (Doc ID 470758.1)