Як вставити (файл) дані в колонку bytea PostgreSQL?


38

Це питання не стосується Bytea v. Oid v. Blobs v. Великих предметів тощо.

У мене є таблиця, що містить integerполе первинного ключа та byteaполе. Я хотів би ввести дані в byteaполе. Імовірно, це можна зробити однією з PL/мов, і я можу розглянути це PL/Pythonв майбутньому.

Оскільки я ще тестую і експериментую, я просто хотів би вставити дані з файлу (на сервері), використовуючи "стандартні" оператори SQL. Мені відомо, що лише адміністратори з дозволом на запис на сервер зможуть вставляти дані так, як мені хотілося б. На цьому етапі мене це не хвилює, оскільки користувачі зараз не вставлятимуть byteaдані. Я шукав різні сайти StackExchange, архіви PostgreSQL та Інтернет загалом, але не зміг знайти відповідь.

Редагувати: Ця дискусія з 2008 року передбачає, що те, що я хочу зробити, неможливо. Як byteaтоді використовуються поля?

Редагувати: На подібне запитання від 2005 року залишається без відповіді.

Вирішено: Дані, наведені тут на psycopgвеб-сайті, послужили основою для рішення, яке я написав у Python. Можливо також можливе вставлення двійкових даних у byteaстовпчик за допомогою PL/Python. Я не знаю, чи можливо це за допомогою "чистого" SQL.


1
Посилання на документи psycopg розірвано, і моє редагування, здається, було відхилено (!?). Ось поточне місцезнаходження .
Aryeh Leib Taurog

@AryehLeibTaurog: Дякую Я відхилив редагування, оскільки мені було не ясно, що ваш змінений текст - це гіперпосилання. Якщо ви хочете зробити редагування ще раз, я схвалюю його.
SabreWolfy

@Andriy_M Чому ви вважаєте, що "Це редагування відхиляється від початкового наміру публікації". (Правка зроблена інформатиком01?)
miracle173

@ miracle173: Тому що у мене склалося враження, що деякі із запропонованих тегів не мають значення (ну, власне, лише один blob). Якщо це була помилка, я щиро вибачаюся.
Андрій М

Відповіді:


27

як суперпользователь:

create or replace function bytea_import(p_path text, p_result out bytea) 
                   language plpgsql as $$
declare
  l_oid oid;
begin
  select lo_import(p_path) into l_oid;
  select lo_get(l_oid) INTO p_result;
  perform lo_unlink(l_oid);
end;$$;

lo_get було введено в 9.4, тож для старих версій вам знадобиться:

create or replace function bytea_import(p_path text, p_result out bytea) 
                   language plpgsql as $$
declare
  l_oid oid;
  r record;
begin
  p_result := '';
  select lo_import(p_path) into l_oid;
  for r in ( select data 
             from pg_largeobject 
             where loid = l_oid 
             order by pageno ) loop
    p_result = p_result || r.data;
  end loop;
  perform lo_unlink(l_oid);
end;$$;

потім:

insert into my_table(bytea_data) select bytea_import('/my/file.name');

Для зворотного процесу, я не пробував це , але якщо він працює, lo_export буде все , що вам потрібно
Джек Дуглас


15

Це рішення не настільки ефективне з точки зору виконання, але це тривіально просто порівняно із створенням власних заголовків COPY BINARY. Крім того, він не вимагає ніяких бібліотек або мов скриптів за межами bash.

Спочатку перетворіть файл у шістнадцятковий, подвоївши розмір файлу. xxd -pзближує нас, але це втягує у деякі набридливі нові рядки, про які ми маємо піклуватися:

xxd -p /path/file.bin | tr -d '\n' > /path/file.hex

Далі імпортуйте дані в PostgreSQL як дуже велике textполе. Цей тип містить до одного ГБ на кожне значення поля, тому ми повинні бути в порядку для більшості цілей:

CREATE TABLE hexdump (hex text); COPY hexdump FROM '/path/file.hex';

Тепер, коли наші дані - це безмежно велика шістнадцятковий рядок, ми використовуємо PostgresQL, decodeщоб перетворити їх у byteaтип:

CREATE TABLE bindump AS SELECT decode(hex, 'hex') FROM hexdump;

Це рішення призводить до того, що \ n символів буде видалено з файлу.
SabreWolfy

2
SabreWolfy: Ні, це не так. Операція tr -d '\n'працює на виході xxd, який кодує двійковий вміст вхідного коду як шістнадцяткові символи ASCII (0-9 та af). xxd також трапляється через регулярні проміжки каналів вихідних рядків, щоб зробити висновок зрозумілим для людини, але в цьому випадку ми хочемо їх видалити. Потокові канали в оригінальних даних будуть у шістнадцятковій формі та залишатимуться без змін.
goodside

5

Відповідь з XXD хороший і для маленьких файлів, дуже швидко. Нижче наведено приклад сценарію, який я використовую.

xxd  -p /home/user/myimage.png | tr -d '\n' > /tmp/image.hex
echo "
    -- CREATE TABLE hexdump (hex text);
    DELETE FROM hexdump;
    COPY hexdump FROM '/tmp/image.hex';

    -- CREATE TABLE bindump (binarydump bytea);
    DELETE FROM bindump;

    INSERT INTO bindump (binarydump)  
    (SELECT decode(hex, 'hex') FROM hexdump limit 1);

    UPDATE users 
    SET image= 
    (
        SELECT decode(hex, 'hex') 
        FROM hexdump LIMIT 1
    )  
    WHERE id=15489 ;
    " | psql mydatabase

1

Використовуйте функцію Postgres COPY BINARY . Це в цілому еквівалентно зовнішнім таблицям Oracle .


Спасибі. Посилання, яке ви надали, вказує на те, що дані повинні бути або у форматі бінарної таблиці ASCII, або у PostgreSQL. Далі на сторінці згадується, що формат бінарної таблиці спочатку створюється командою COPY TO. Чи дозволить мені один із цих підходів вставити бінарний файл (PDF, документ, електронну таблицю) у byteaстовпець?
SabreWolfy

Документація PostgreSQL на COPY BINARY ( postgresql.org/docs/8.4/interactive/sql-copy.html ) вказує, що при вставці бінарних даних потрібен спеціальний заголовок файлу. Чи потрібно мені скласти цей заголовок і додати його до двійкових даних? Це здається дещо складним для простого зберігання рядка двійкових даних.
SabreWolfy

Хм, тепер, коли ви це згадуєте, я не впевнений, я просто згадав команду і припустив, що це зробить. Можливо, PL / все, що це єдиний спосіб зробити це.
Гай
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.