Làm cách nào để chèn (tệp) dữ liệu vào cột bygea PostgreSQL?


37

Câu hỏi này không phải là về bytea v. Oid v. Blobs v. Các đối tượng lớn, v.v.

Tôi có một bảng chứa trường khóa chính integerbyteatrường. Tôi muốn nhập dữ liệu vào byteatrường. Điều này có thể, có lẽ, được thực hiện bởi một trong những PL/ngôn ngữ, và tôi có thể xem xét việc này PL/Pythontrong tương lai.

Vì tôi vẫn đang thử nghiệm và thử nghiệm, tôi chỉ muốn chèn dữ liệu từ một tệp (trên máy chủ) bằng cách sử dụng các câu lệnh SQL "chuẩn". Tôi biết rằng chỉ những quản trị viên có quyền ghi trên máy chủ mới có thể chèn dữ liệu theo cách tôi muốn. Tôi không quan tâm đến điều đó ở giai đoạn này vì hiện tại người dùng sẽ không chèn byteadữ liệu. Tôi đã tìm kiếm các trang web StackExchange khác nhau, Lưu trữ PostgreSQL và Internet nói chung, nhưng không thể tìm thấy câu trả lời.

Chỉnh sửa: Cuộc thảo luận này từ năm 2008 ngụ ý rằng những gì tôi muốn làm là không thể. Làm thế nào là byteacác lĩnh vực được sử dụng sau đó?

Chỉnh sửa: Đây câu hỏi tương tự từ năm 2005 vẫn chưa được trả lời.

Đã giải quyết: Các chi tiết được cung cấp ở đây trên psycopgtrang web đã cung cấp cơ sở cho giải pháp tôi đã viết bằng Python. Cũng có thể chèn dữ liệu nhị phân vào một byteacột bằng cách sử dụng PL/Python. Tôi không biết nếu điều này có thể sử dụng SQL "thuần túy".


1
Liên kết đến các tài liệu psycopg bị hỏng và chỉnh sửa của tôi dường như đã bị từ chối (!?). Đây là vị trí hiện tại .
Aryeh Leib Taurog

@AryehLeibTaurog: Cảm ơn. Tôi đã từ chối chỉnh sửa vì tôi không rõ văn bản thay đổi của bạn là một siêu liên kết. Nếu bạn muốn chỉnh sửa lại, tôi sẽ phê duyệt.
SabreWolfy

@Andriy_M Tại sao bạn nghĩ rằng "Bản chỉnh sửa này lệch khỏi mục đích ban đầu của bài đăng." (Bản chỉnh sửa được thực hiện bởi
notifyatik01

@ miracle173: Bởi vì tôi có ấn tượng rằng một số thẻ được đề xuất là không liên quan (thực sự chỉ là một thẻ, blob). Nếu đó là một sai lầm, tôi chân thành xin lỗi.
Andriy M

Câu trả lời:


26

như siêu người dùng:

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 đã được giới thiệu vào 9,4 vì vậy đối với các phiên bản cũ hơn, bạn sẽ cần:

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

sau đó:

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

Đối với quy trình ngược lại, tôi đã không thử điều này , nhưng nếu nó hoạt động, lo_export sẽ là tất cả những gì bạn cần
Jack Douglas


15

Giải pháp này không thực sự hiệu quả về mặt thời gian chạy, nhưng nó dễ dàng so với việc tạo tiêu đề của riêng bạn COPY BINARY. Hơn nữa, nó không yêu cầu bất kỳ thư viện hoặc ngôn ngữ kịch bản bên ngoài bash.

Đầu tiên, chuyển đổi tệp thành hexdump, nhân đôi kích thước của tệp. xxd -plàm cho chúng ta khá gần, nhưng nó ném vào một số dòng mới gây phiền nhiễu mà chúng ta phải quan tâm:

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

Tiếp theo, nhập dữ liệu trong PostgreSQL dưới dạng một trường rất lớn text. Loại này chứa tối đa một GB cho mỗi giá trị trường, vì vậy chúng tôi sẽ ổn cho hầu hết các mục đích:

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

Bây giờ dữ liệu của chúng tôi là một chuỗi hex lớn vô cớ, chúng tôi sử dụng PostgresQL decodeđể biến nó thành một bytealoại:

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

Giải pháp này dẫn đến việc \ n ký tự bị xóa khỏi tệp.
SabreWolfy

2
SabreWolfy: Không, không. Hoạt tr -d '\n'động trên đầu ra của xxd, mã hóa nội dung nhị phân của đầu vào dưới dạng các ký tự thập lục phân ASCII (0-9 và af). xxd cũng xảy ra với các nguồn cấp dữ liệu đầu ra đều đặn để làm cho đầu ra có thể đọc được, nhưng trong trường hợp này chúng tôi muốn loại bỏ chúng. Nguồn cấp dữ liệu trong dữ liệu gốc sẽ ở dạng hex và sẽ không bị ảnh hưởng.
hóa

5

Câu trả lời với xxd là tốt và, đối với các tệp nhỏ, rất nhanh. Dưới đây là một kịch bản ví dụ mà tôi đang sử dụng.

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

Sử dụng chức năng Postgres SAO CHÉP . Điều này tương đương với các bảng bên ngoài của Oracle .


Cảm ơn. Liên kết bạn đưa ra chỉ ra rằng dữ liệu phải ở định dạng bảng nhị phân của ASCII hoặc PostgreQuery. Tiếp tục xuống trang, đề cập đến việc định dạng bảng nhị phân được tạo trước tiên bằng lệnh COPY TO. Một trong những cách tiếp cận này có cho phép tôi chèn một tệp nhị phân (PDF, tài liệu, bảng tính) vào một byteacột không?
SabreWolfy

Tài liệu PostgreSQL về SAO CHÉP ( postgresql.org/docs/8.4/interactive/sql-copy.html ) chỉ ra rằng một tiêu đề tệp đặc biệt là bắt buộc khi chèn dữ liệu nhị phân. Tôi có cần xây dựng tiêu đề này và nối nó vào dữ liệu nhị phân không? Điều đó có vẻ hơi phức tạp khi chỉ đơn giản là lưu trữ một chuỗi dữ liệu nhị phân.
SabreWolfy

Hmm, bây giờ bạn đề cập đến nó tôi không chắc chắn, tôi chỉ nhớ lệnh và cho rằng nó sẽ làm điều đó. Có lẽ PL / bất cứ điều gì là cách duy nhất để làm điều đó.
Gaius
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.