【问题标题】:how to transfer CLOB data from one database to another remote ORACLE database having DBLinks如何将 CLOB 数据从一个数据库传输到另一个具有 DBLinks 的远程 ORACLE 数据库
【发布时间】:2018-04-11 09:09:57
【问题描述】:

问题是,如何将 CLOB 数据从一个源数据库传输到另一个具有 DBLinks 的 Oracle 数据库。

Oracle 无法使用 DBLinks 传输 CLOB 数据,所以除了:将 Oracle 中的字段扩展为 Varchar2 32.767 个字符(Oracle 12 的新功能)之外,我们还有哪些解决方案。

【问题讨论】:

  • 我认为限制适用于已弃用的 LONG 列,而不适用于 CLOB 列?

标签: oracle clob


【解决方案1】:

Howd 在 4 年前可能有正确的方法,但我需要将他更新为以下内容才能使其工作(我简化了他以供自己使用,因此以下内容可能无法编译或工作,但你明白了,在 12.1.0.2.0 中不再需要第一个查询):

create or replace function dblink_clob(
    p_dblink    in varchar2
  , v_remote_table in varchar2
  , p_clob_col  in varchar2
  , p_rid       in urowid
)
return clob is
    /**  A function to fetch a CLOB column over a dblink  **/
    /**  Laurence Prescott 25-Aug-17  **/
    /**  select dblink_clob('some_dblink', 'some_clob_column', rowid)
           from some_table@some_dblink;
         Note: Does not work on tables that have a virtual column (eg. xmltype).
    **/

    c_chunk_size    constant pls_integer := 4000;
    v_chunk         varchar2(4000);
    v_clob          clob;
    v_pos           pls_integer := 1;
begin
    dbms_lob.createtemporary(v_clob, true, dbms_lob.call);
    loop
        execute immediate 
            'select dbms_lob.substr@' ||p_dblink|| '(' ||p_clob_col|| ', ' ||c_chunk_size
         || ', ' ||v_pos|| ') from ' ||v_remote_table|| '@' ||p_dblink|| ' where rowid = :rid '
        into v_chunk using p_rid;
        begin dbms_lob.append(v_clob, v_chunk);
        exception when others then
            if sqlcode = -6502 then exit; else raise; end if;
        end;
        if length(v_chunk) < c_chunk_size then exit; end if;
        v_pos := v_pos + c_chunk_size;
    end loop;
    return v_clob;
end dblink_clob;

【讨论】:

    【解决方案2】:

    我发布了一个通过 dblink 查询 CLOB 和 BLOB 的 Github 项目。 https://github.com/HowdPrescott/Lob_Over_DBLink

    这是独立函数中的 CLOB 部分:

    create or replace function dblink_clob(
        p_dblink    in varchar2
      , p_clob_col  in varchar2
      , p_rid       in urowid
    )
    return clob is
        /**  A function to fetch a CLOB column over a dblink  **/
        /**  Laurence Prescott 25-Aug-17  **/
        /**  select dblink_clob('some_dblink', 'some_clob_column', rowid)
               from some_table@some_dblink;
             Note: Does not work on tables that have a virtual column (eg. xmltype).
        **/
    
        c_chunk_size    constant pls_integer := 4000;
        v_chunk         varchar2(4000);
        v_remote_table  varchar2(128);
        v_clob          clob;
        v_pos           pls_integer := 1;
    begin
        dbms_lob.createtemporary(v_clob, true, dbms_lob.call);
        execute immediate 'select object_name from user_objects@' ||p_dblink
                       || ' where data_object_id = dbms_rowid.rowid_object(:bv_rid) '
        into v_remote_table using cast (p_rid as rowid);
        loop
            execute immediate 
                'select dbms_lob.substr@' ||p_dblink|| '(' ||p_clob_col|| ', ' ||c_chunk_size
             || ', ' ||v_pos|| ') from ' ||v_remote_table|| '@' ||p_dblink|| ' where rowid = :rid '
            into v_chunk using p_rid;
            begin dbms_lob.append(v_clob, v_chunk);
            exception when others then
                if sqlcode = -6502 then exit; else raise; end if;
            end;
            if length(v_chunk) < c_chunk_size then exit; end if;
            v_pos := v_pos + c_chunk_size;
        end loop;
        return v_clob;
    end dblink_clob;
    

    我认为这个例子是不言自明的,但这里有一些描述。
    该函数依赖于这样一个事实,即您可以通过 dblink 在远程数据库上调用函数/过程 - 在本例中为 dbms_lob.substr()
    首先,它通过使用其对象 id(编码到 rowid 中)找到远程表名称。这样就不必将远程表名称作为另一个参数传递。
    另请注意,p_rid 参数是一个 urowid,因为它是来自远程数据库的 rowid。这就是为什么它需要被投射。
    然后将 CLOB 提取并重建为 4000 字节的块,这是 PL/SQL 中的最大 varchar2 大小。这些块是 varchar2 的,可以通过 dblink 传递。
    if length(v_chunk) 子句在读取完最后一个 CLOB 后得到满足(那么“块”缓冲区将不会被填充)。
    当 CLOB 的长度是 4000 的倍数时,需要 ORA-06502 的异常捕获,即使没有更多数据,也无法满足“if”子句。 您可以仅依靠此捕获并完全删除“if”子句。但是我做了一些性能测试,发现在大多数情况下最好还是保留它。

    【讨论】:

      【解决方案3】:

      首先你需要临时表:

      create global temporary table TBL_TMP_CLOB
      (
        c_clob CLOB
      )
      

      第二次使用“从选择插入”:

      INSERT INTO schema.remote_table@dblink(rem_clob) SELECT * FROM TBL_TMP_CLOB; 
      

      【讨论】:

      • 这个全局临时表应该存储什么?
      • @Sylwia Krakowska 临时表应该存储 CLOB 数据,您希望将其传输到远程数据库
      • 我无法正确解释它为什么起作用,但我在我的项目中使用了这种方法。
      • 所以临时表应该在源端创建,是吗?
      • @Sylwia Krakowska 是的,是的。我认为这个link 可以帮助你。
      猜你喜欢
      • 1970-01-01
      • 2012-04-19
      • 1970-01-01
      • 2016-10-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-25
      相关资源
      最近更新 更多