Wie fügt ich (Datei-) Daten in eine PostgreSQL -Bytea -Spalte ein?
-
16-10-2019 - |
Frage
In dieser Frage geht es nicht um Bytea v. Oid v. Blobs v. Große Objekte usw.
Ich habe eine Tabelle mit einem Primärschlüssel integer
Feld und a bytea
aufstellen. Ich möchte Daten in die eingeben bytea
aufstellen. Dies kann vermutlich von einem der von einem der von erledigt werden PL/
Sprachen, und ich kann mir das ansehen PL/Python
in der Zukunft.
Während ich noch teste und experimentiere, möchte ich einfach Daten aus einer Datei (auf dem Server) mit "Standard" -S -SQL -Anweisungen einfügen. Ich bin mir bewusst, dass nur Administratoren mit Schreibberechtigung auf dem Server Daten so einfügen könnten, wie ich es möchte. Ich bin in dieser Phase nicht besorgt darüber, da die Benutzer nicht einfügen würden bytea
Daten derzeit. Ich habe die verschiedenen Stackexchange -Websites, die PostgreSQL -Archive und das Internet im Allgemeinen durchsucht, konnten aber keine Antwort finden.
Bearbeiten: Dies Die Diskussion von 2008 impliziert, dass das, was ich tun möchte, nicht möglich ist. Wie bist bytea
Felder dann verwendet dann?
Bearbeiten: Dies Eine ähnliche Frage aus dem Jahr 2005 bleibt unbeantwortet.
Gelöst: Die angegebenen Details hier auf der psycopg
Die Website bildete die Grundlage für eine Lösung, die ich in Python geschrieben habe. Es kann auch möglich sein, Binärdaten in a einzufügen bytea
Spalte verwendet PL/Python
. Ich weiß nicht, ob dies mit "reinem" SQL möglich ist.
Lösung
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, also für ältere Versionen, die Sie brauchen 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');
Andere Tipps
Verwenden 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);
Diese Lösung ist in Bezug auf die Laufzeit nicht gerade effizient, aber sie ist im Vergleich zu Ihren eigenen Headern für eindeutig einfach COPY BINARY
. Darüber hinaus sind keine Bibliotheken oder Skriptsprachen außerhalb von Bash erforderlich.
Konvertieren Sie zuerst die Datei in einen Hexdump, wodurch die Größe der Datei verdoppelt wird. xxd -p
Bringt uns ziemlich nah, aber es gibt einige nervige Neulinge ein, um die wir uns kümmern müssen:
xxd -p /path/file.bin | tr -d '\n' > /path/file.hex
Importieren Sie die Daten als nächstes in PostgreSQL als sehr große text
aufstellen. Dieser Typ hält bis zu einem 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 unentgeltlich große Hex -Zeichenfolge sind, verwenden wir Postgresqls decode
um es in eine zu bringen bytea
Typ:
CREATE TABLE bindump AS SELECT decode(hex, 'hex') FROM hexdump;
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
Verwenden Sie die Postgres Binär kopieren Funktion. Dies entspricht weitgehend der Oracle's externe Tische.