как перенести данные CLOB из одной базы данных в другую удаленную базу данных ORACLE, имеющую DBLinks

Проблема в том, как перенести данные CLOB из одной исходной базы данных в другую базу данных Oracle, имеющую DBLinks.

Oracle не может передавать данные CLOB с помощью DBLinks, поэтому какое решение мы можем иметь, кроме: расширения полей в Oracle до 32,767 символов Varchar2 (новая функция Oracle 12).


person Sylwia Krakowska    schedule 30.10.2017    source источник
comment
Я думал, что ограничение распространяется на устаревшие LONG столбцы, а не на CLOB столбцы?   -  person a_horse_with_no_name    schedule 30.10.2017


Ответы (2)


Для начала вам понадобится временная таблица:

create global temporary table TBL_TMP_CLOB
(
  c_clob CLOB
)

При втором использовании «Вставить из выбора»:

INSERT INTO schema.remote_table@dblink(rem_clob) SELECT * FROM TBL_TMP_CLOB; 
person I3rutt    schedule 30.10.2017
comment
Что должна хранить эта глобальная временная таблица? - person Sylwia Krakowska; 30.10.2017
comment
Во временной таблице @Sylwia Krakowska хранятся данные CLOB, которые вы хотите передать в удаленную БД. - person I3rutt; 30.10.2017
comment
Я не могу правильно объяснить, почему это работает, но я использую этот метод в своих проектах. - person I3rutt; 30.10.2017
comment
так что временная таблица должна быть создана на стороне источника, не так ли? - person Sylwia Krakowska; 30.10.2017
comment
@Sylwia Krakowska да, это так. Я думаю, эта ссылка мог бы помочь вам. - person I3rutt; 30.10.2017

Я выпустил проект Github, который запрашивает CLOB и BLOB через dblink. 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 ().
Сначала он находит имя удаленной таблицы по идентификатору объекта (который закодирован в rowid). Это избавляет от необходимости передавать имя удаленной таблицы в качестве другого параметра.
Также обратите внимание, что параметр p_rid - это urowid, поскольку это rowid из удаленной БД. Вот почему его необходимо преобразовать.
Затем CLOB извлекается и перестраивается в блоки по 4000 байт, что является максимальным размером varchar2 в PL / SQL. Эти блоки являются varchar2 и могут передаваться по dblink.
Предложение if length (v_chunk) ‹c_chunk_size ... удовлетворяется после того, как был прочитан последний объект CLOB (тогда" chunk "буфер не будет заполнен).
Перехват исключения для ORA-06502 необходим, когда длина CLOB кратна 4000, тогда условие" if "не выполняется, хотя данных больше нет. Вы можете просто положиться на эту уловку и полностью удалить предложение «if». Но я провел небольшое тестирование производительности и обнаружил, что в большинстве случаев лучше оставить его.

person Howd    schedule 07.11.2017