2016-04-22 2 views
0

У меня есть файл размером 450 МБ, и я хочу вставить его в столбец Blob в таблице Oracle. Я попытался вставить содержимое файла как строку, но он говорит, что «строковый литерал слишком длинный». Кто-нибудь может предложить элегантный способ вставки в таблицу. При условии: у меня нет доступа к каталогу на сервере базы данных, у меня есть файл xml в моей локальной системеВставьте большой файл xml как blob в таблицу oracle

+0

Используйте http://blogs.perficient.com/delivery/blog/2012/05/29/insert-a-long-xml-string-to-db-table-with-plsql/ –

ответ

1

Вы можете преобразовать xml-файл в скрипт sql, выполнив соответствующий анонимный блок PLSQL. Загрузка этого скрипта в db будет заполнять blob.

Основная идея состоит в том, чтобы разбить файл xml на куски 2000 символов. Первый фрагмент может быть непосредственно вставлен в столбец blob целевой таблицы. Каждый другой будет добавлен оператором обновления, использующим процедуру пакета dbms_lob.fragment_insert. !!! ПРЕДУПРЕЖДЕНИЕ: Это не рекомендуется!. Лучше получите dba, чтобы загрузить его для вас!

Пример:

  • Предположения:

    • Целевая таблица имеет 2 колонки, рК и BLOB.
    • pk is 42.
    • 2000 - размер образца, считающийся подходящим. Технически, dbms_lob.fragment_insert обрабатывает до 32767, однако другие задействованные инструменты (например, sqlplus) могут иметь более жесткие ограничения на длину строки.
  • Код:

    declare 
        l_b BLOB; 
    begin 
        insert 
         into 
        t_target (c_pk, c_blob) 
        values (42, utl_raw.cast_to_raw('<This literal contains the first 2000 (chunksize) characters of the xml file>')) 
    returning c_blob 
        into l_b 
         ; 
    
    dbms_lob.fragment_insert (l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset 2000>')); 
    dbms_lob.fragment_insert (l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset 4000>')); 
    dbms_lob.fragment_insert (l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset 6000>')); 
    ... 
    dbms_lob.fragment_insert (l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains the last chunk>')); 
    
    commit; 
    end; 
    /
    show err 
    

Подготовительные работы

  1. Вы должны убедиться, что ни одна цитата не происходит внутри вашего файла XML. В противном случае сгенерированный код PLSQL будет содержать синтаксические ошибки.

    Если одинарные кавычки не используются в качестве разделителей значений атрибутов, просто замените их на числовой объект &x#28;.

  2. Создать большую часть анонимного PLSQL

методы для вставки данных в файл через регулярные промежутки времени представлены в this SO question, наиболее гибкий подход намечаются in this answer. Вместо того, чтобы символы новой строки, вставьте следующую строку, вставленный:

"'));\n  dbms_lob.fragment_insert (l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('" 

Остальная часть анонимного PLSQL могут быть скопированы/написанный вручную.

Caveat

как есть, размер сценария будет иметь такую ​​же величину, что и исходный XML и блок PLSQL будет содержать 200k + строк. Скорее всего, вы столкнетесь с некоторыми ограничениями задействованных инструментов. Тем не менее, этот сценарий может быть разбит на произвольное число кусков следующим образом:

declare 
    l_b BLOB; 
begin 
    select c_blob 
     into l_b 
     from t_target 
    where c_pk = 42 
     ; 

dbms_lob.fragment_insert (l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset <k>*2000>')); 
dbms_lob.fragment_insert (l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset (<k>+1)*2000>')); 
dbms_lob.fragment_insert (l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset (<k>+2)*2000>')); 
... 
dbms_lob.fragment_insert (l_b, 2000, 1+dbms_lob.getlength(l_b), utl_raw.cast_to_raw('<This literal contains 2000 characters starting at [0-based] offset (<k>+<n_k>)*2000>')); 
end; 
/
show err 

И еще раз: !!! ПРЕДУПРЕЖДЕНИЕ: Это не рекомендуется!. Лучше получите dba, чтобы загрузить его для вас!

1

Как насчет написания небольшой программы на любых языках, которая умеет читать файл и вставлять запрос в таблицу.

+0

Это звучит проще всего. Программу можно выполнить с помощью PLSQL непосредственно в базе данных Oracle. Но это может потребовать работы. –

+0

Я имел в виду другие языки - java, python ... Не стоит тратить больше часа –

2

Предположим, вы немного ищете и натыкаетесь на search result: вы найдете страницу с кодом PL/SQL.

CREATE OR REPLACE DIRECTORY test_dir AS '<path_on_db_server>'; 

DECLARE 
    l_bfile BFILE; 
    l_blob BLOB; 
BEGIN 
    -- this depends on your table definition, col1 being the BLOB column 
    INSERT INTO tab1 (col1, col2) VALUES (empty_blob(), 'test1') 
    RETURN col1 INTO l_blob; 

    l_bfile := BFILENAME('test_dir', 'my.xml'); 
    DBMS_LOB.fileopen(l_bfile, Dbms_Lob.File_Readonly); 
    DBMS_LOB.loadfromfile(l_blob, l_bfile, DBMS_LOB.getlength(l_bfile)); 
    DBMS_LOB.fileclose(l_bfile); 

    COMMIT; 
END; 

Тогда вы попробуете его (после того, как вы поместите файл test.xml на сервере в <path_on_db_server> и заверил, что oracle пользователь имеет доступ к файлу).

Смежные вопросы