it-swarm.dev

Jak wstawić (plik) dane do kolumny bajtów PostgreSQL?

To pytanie nie dotyczy bytea v. Oid v. Blob v. Dużych obiektów itp.

Mam tabelę zawierającą klucz podstawowy integer pole i _ bytea pole. Chciałbym wprowadzić dane w polu bytea. Można to zrobić prawdopodobnie przez jeden z PL/ języki, i mogę to zrobić za pomocą PL/Python w przyszłości.

Ponieważ wciąż testuję i eksperymentuję, chciałbym po prostu wstawić dane z pliku (na serwerze) przy użyciu „standardowych” instrukcji SQL. Wiem, że tylko administratorzy z uprawnieniami do zapisu na serwerze mogliby wstawiać dane w sposób, w jaki chciałbym. Nie martwię się tym na tym etapie, ponieważ użytkownicy nie wstawiliby obecnie bytea danych. Przeszukałem różne strony StackExchange, archiwa PostgreSQL i ogólnie Internet, ale nie byłem w stanie znaleźć odpowiedzi.

Edycja: This dyskusja z 2008 roku oznacza, że ​​to, co chcę zrobić, nie jest możliwe. Jak wtedy wykorzystywane są pola bytea?

Edycja: This podobne pytanie z 2005 roku pozostaje bez odpowiedzi.

Rozwiązany: Podane szczegóły tutaj na stronie psycopg stanowiły podstawę rozwiązania, które napisałem w Pythonie. Możliwe jest również wstawienie danych binarnych do kolumny bytea przy użyciu PL/Python. Nie wiem, czy jest to możliwe przy użyciu „czystego” SQL.

40
SabreWolfy

jako administrator:

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 został wprowadzony w wersji 9.4, więc dla starszych wersji potrzebujesz:

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

następnie:

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

Użyj pg_read_file('location_of file')::bytea.

Na przykład,

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

Ręcznie

19
User2397

To rozwiązanie nie jest dokładnie wydajne pod względem czasu działania, ale jest banalnie proste w porównaniu do tworzenia własnych nagłówków dla COPY BINARY. Co więcej, nie wymaga żadnych bibliotek ani języków skryptowych poza bash.

Najpierw przekonwertuj plik na zrzut heksowy, podwajając rozmiar pliku. xxd -p przybliża nas do siebie, ale wprowadza pewne irytujące nowości, którymi musimy się zająć:

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

Następnie zaimportuj dane do PostgreSQL jako bardzo duże pole text. Ten typ mieści do jednego GB na wartość pola, więc w większości przypadków powinniśmy być w porządku:

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

Teraz, gdy nasze dane są nieskończenie dużym ciągiem szesnastkowym, używamy decode PostgresQL, aby uzyskać typ bytea:

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

odpowiedź za pomocą xxd jest ładne, a dla małych plików bardzo szybkie. Poniżej znajduje się przykładowy skrypt, którego używam.

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

Użyj funkcji Postgres COPY BINARY . Jest to zasadniczo równoważne z zewnętrznymi tabelami Oracle .

1
Gaius

Oto jak to zrobić bez uprawnień administratora (np. Na Heroku).

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

Możesz użyć \lo_list, aby zobaczyć duże obiekty, i \lo_unlink, aby je usunąć. Pole contract w moim przykładzie to bytea.

     Column      |            Type             |
contract         | bytea                       |
0
Chloe