通过DBLink移动XML

时间:2011-06-07 16:00:27

标签: oracle plsql xmltype dblink

我正在尝试通过dblink移动一些数据,其中一列是XMLType列。代码如下所示:

begin
    delete from some_schema.some_remote_tab@src_2_trg_dblink;
    INSERT INTO some_schema.some_remote_tab@src_2_trg_dblink(id, code, gen_date, xml_data)
    SELECT id, code, gen_date, xml_data
    FROM local_table;
end;

Oracle会返回以下错误:

ORA-02055: distributed update operation failed; rollback required
ORA-22804: remote operations not permitted on object tables or user-defined type columns

对ORA-22804的一些研究表明,由于XMLType列,我可能会收到此错误,但我不知道如何解决此问题。

(Oracle 10g)

5 个答案:

答案 0 :(得分:2)

我们得到ORA-22804,因为我们Oracle数据库中每个Type的实例都有一个OID,它在数据库中是唯一的。我们无法将该OID转移到另一个数据库;在尝试导入具有用户定义类型的模式之前,这让我感到悲痛。我没有意识到它也影响了XMLType,但它是一个Object,所以这并不奇怪。

解决方案很糟糕:您必须将XML卸载到本地数据库中的文本中,然后将其转换回远程数据库中的XML。

我目前没有分布式数据库设置来测试,但如果你很幸运,它可能会有效:

INSERT INTO some_schema.some_remote_tab@src_2_trg_dblink(id, code, gen_date, xml_data)
SELECT id, code, gen_date, xmltype ( xml_data.asClobVal() )
FROM local_table;

如果asClobVal()方法不起作用,则可能需要使用SQL函数XMLSERIALIZE()。

XMLSerialize(DOCUMENT xml_data AS CLOB) 

如果你真的不走运,你将无法在单个SQL语句中执行此操作,并且您必须使用PL / SQL解决它。在某种程度上,这取决于您使用的数据库版本;版本越新,你就越有可能在SQL而不是PL / SQL中使用它。

答案 1 :(得分:1)

尝试以相反的方式做到这一点。这是登录到远程数据库,创建到本地数据库的dblink,并执行这样的插入

INSERT INTO remote_schema.some_remote_tab(id, code, gen_date, xml_data) 
SELECT id, code, gen_date, xml_data
    FROM local_table@dblink_to_local_db;

答案 2 :(得分:0)

而是执行数据拉取。

  1. 在远程数据库B创建数据提取过程。
  2. 创建同义词并向dblink用户提供授权。
  3. 从数据库A(源)调用远程过程在数据库A(源)执行提交。
  4. (同时..等待oracle找到一些解决方案,以便将来在dblink上执行XML的PUSH)

    在远程站点数据库B

    创建过程
    CREATE OR REPLACE PROCEDURE PR_REMOTE(OP_TOTAL_COUNT OUT NUMBER) IS
    BEGIN
    
      INSERT /*+ DRIVING_SITE(src) */
      INTO REMOTE_TABLE TGT_B
        (XMLDATA_COL)
        SELECT SRC.XMLDATA FROM LOCAL_TABLE@TGT2SRC_DBLINK SRC;
    
      OP_TOTAL_COUNT := SQL%ROWCOUNT;
    
    END;
    

    从数据库A

    调用该过程
    DECLARE
      V_COUNT NUMBER := 0;
    BEGIN
      PR_REMOTE(V_COUNT);
      COMMIT;
    END;
    

答案 3 :(得分:0)

我遇到了与SQL服务器的异构数据库链接相同的问题。

使用xmltype.getStringVal()结束插入SQL Server端的VARCHAR列,因为数据不到4000个字符。

如果超过4000个字符,还有xmltype.getClobVal(),但我还没有对其进行测试。

答案 4 :(得分:0)

“xml-> text-> xml”链可能很复杂,但在某些情况下可能会有所帮助(例如,当插入不是选项但仅更新时)。 您可以尝试使用varchar列的“n”和平(在目标表或不同的列中,远程数据库上的不同模式中的perheaps),其中“n”是: ceil(max(dbms_lob.getlength(MyXmlColumn))/ 4000)

然后您可以将这些片段传输到远程临时字段:

public class OuterClass {

  int i;

  public void method1() {
    System.out.println("Inside Method 1");
  }

  class InnerClass {
    int j;

    public void method2() {
      System.out.println("Inside Method 2");
    }
  }

  public static void main(String[] args) {
    // To instantiate an inner class, you must first instantiate the outer class
    OuterClass outerObject = new OuterClass();
    outerObject.method1();

    // Then, create the inner object within the outer object
    OuterClass.InnerClass innerObject = outerObject.new InnerClass();
    innerObject.method2();
  }

}

XmlType可以从这样的片段重新组成:

insert into RemoteSchema.MyTable(Id, XmlPart1, XmlPart2,...)
(select 1 /*some Id*/,
        dbma_lob.substr(MyXmlColumn.getclobval(), 4000, 1),
        dbma_lob.substr(MyXmlColumn.getclobval(), 4000, 4001),
        ...
 from LocalSchema.MyTable

最后使用结果更新remothe架构中的任何其他表,如:

create or replace function concat_to_xml(p_id number)
return xmltype
is
  xml_lob clob;
  xml xmltype;
begin
  dbms_lob.createtemporary(xml_lob, true);
  for r in (select XmlPart1, XmlPart2, ... from RemoteSchema.MyTable where Id = p_id)
  loop
    if r.XmlPart1 is not null then
      dbms_lob.writeappend(xml_lob, length(r.XmlPart1), r.XmlPart1);
    end if;
    if r.XmlPart2 is not null then
      dbms_lob.writeappend(xml_lob, length(r.XmlPart2), r.XmlPart2);
    end if;
    ...
  end loop;
  xml := xmltype(xml_lob);
  dbms_lob.freetemporary(xml_lob);
  return xml;
end;