it-swarm.com.de

Wie füge ich (Datei-) Daten in eine PostgreSQL-Bytea-Spalte ein?

Bei dieser Frage geht es nicht um Bytea v. Oid v. Blobs v. Große Objekte usw.

Ich habe eine Tabelle, die ein Primärschlüsselfeld integer und ein Feld bytea enthält. Ich möchte Daten in das Feld bytea eingeben. Dies kann vermutlich in einer der Sprachen PL/ Durchgeführt werden, und ich werde dies möglicherweise in Zukunft mit PL/Python Ausführen.

Während ich noch teste und experimentiere, möchte ich einfach Daten aus einer Datei (auf dem Server) mit "Standard" -SQL-Anweisungen einfügen. Mir ist bekannt, dass nur Administratoren mit Schreibberechtigung auf dem Server Daten so einfügen können, wie ich es möchte. Darüber bin ich derzeit nicht besorgt, da Benutzer derzeit keine bytea -Daten einfügen würden. Ich habe die verschiedenen StackExchange-Sites, das PostgreSQL-Archiv und das Internet im Allgemeinen durchsucht, konnte jedoch keine Antwort finden.

Bearbeiten: Dies Diskussion aus dem Jahr 2008 impliziert, dass das, was ich tun möchte, nicht möglich ist. Wie werden dann bytea Felder verwendet?

Edit: This ähnliche Frage aus dem Jahr 2005 bleibt unbeantwortet.

Gelöst: Die auf der Website psycopg angegebenen Details hier bildeten die Grundlage für eine von mir geschriebene Lösung in Python. Es kann auch möglich sein, Binärdaten mit PL/Python In eine bytea - Spalte einzufügen. Ich weiß nicht, ob dies mit "reinem" SQL möglich ist.

40
SabreWolfy

als Superuser:

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 wurde in 9.4 eingeführt, sodass Sie für ältere Versionen Folgendes benötigen würden:

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;$$;

dann:

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

Verwenden Sie pg_read_file('location_of file')::bytea.

Zum Beispiel,

create table test(id int, image bytea);
insert into test values (1, pg_read_file('/home/xyz')::bytea);

Handbuch

19
User2397

Diese Lösung ist in Bezug auf die Laufzeit nicht gerade effizient, aber im Vergleich zum Erstellen eigener Header für COPY BINARY Trivial einfach. Außerdem sind keine Bibliotheken oder Skriptsprachen außerhalb von Bash erforderlich.

Konvertieren Sie zunächst die Datei in einen Hexdump und verdoppeln Sie die Größe der Datei. xxd -p Bringt uns ziemlich nahe, aber es wirft einige nervige Zeilenumbrüche auf, um die wir uns kümmern müssen:

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

Importieren Sie als Nächstes die Daten in PostgreSQL als sehr großes text Feld. Dieser Typ fasst bis zu 1 GB pro Feldwert, daher sollten wir für die meisten Zwecke in Ordnung sein:

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

Jetzt, da unsere Daten eine unbegründet große Hex-Zeichenfolge sind, verwenden wir PostgresQLs decode, um sie in einen bytea Typ zu bringen:

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

Das Antwort mit xxd ist schön und für kleine Dateien sehr schnell. Unten ist ein Beispielskript, das ich verwende.

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
5
user1555

Verwenden Sie die Funktion Postgres COPY BINARY . Dies entspricht weitgehend Oracle externe Tabellen .

1
Gaius

Hier erfahren Sie, wie Sie dies ohne Superuser-Berechtigungen tun können (z. B. bei Heroku).

\lo_import '/cygdrive/c/Users/Chloe/Downloads/Contract.pdf'
update contracts set contract = lo_get(:LASTOID) where id = 77;

Sie können \lo_list Verwenden, um die großen Objekte anzuzeigen, und \lo_unlink, Um sie zu löschen. Das Feld contract in meinem Beispiel ist bytea.

     Column      |            Type             |
contract         | bytea                       |
0
Chloe