如何将数据(文件)插入PostgreSQL bytea列?


37

这个问题与bytea v。oid v。blobs v。大物体等无关。

我有一个包含主键integer字段和bytea字段的表。我想在该bytea字段中输入数据。据推测,这可以通过一种PL/语言来完成,PL/Python将来我可能会考虑这样做。

在仍在测试和试验中,我只想使用“标准” SQL语句从文件(服务器上)插入数据。我知道,只有在服务器上具有写权限的管理员才能以我想要的方式插入数据。我现在不担心这一点,因为用户bytea目前不会插入数据。我已经搜索了各种StackExchange网站,PostgreSQL档案库和Internet,但没有找到答案。

编辑: 从2008年的讨论意味着什么,我想做的事情是不可能的。那么如何使用bytea字段?

编辑: 从2005年类似的问题仍然没有答案。

解决:所提供的细节在这里上的psycopg网站,我用Python编写的解决方案提供了基础。也可以使用将二进制数据插入到bytea列中PL/Python。我不知道是否可以使用“纯” SQL。


1
指向psycopg文档的链接已损坏,我的编辑似乎已被拒绝(!?)。 这是当前位置
Aryeh Leib Taurog

@AryehLeibTaurog:谢谢。我拒绝了该编辑,因为我不清楚您更改的文本是一个超链接。如果您想再次进行修改,我会批准。
SabreWolfy 2013年

@Andriy_M为什么您认为“此编辑偏离了帖子的初衷”。(由informatik01完成编辑?)
miracle173

@ miracle173:因为给我留下了一些建议的标签不相关的印象(实际上,只是一个blob)。如果那是一个错误,我表示诚挚的歉意。
Andriy M 2015年

Answers:


26

作为超级用户:

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

接下来,将数据作为很大的text字段导入PostgreSQL 。此类型每个字段值最多可容纳一个GB,因此对于大多数目的,我们应该可以:

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字符从文件中删除。
2011年

2
SabreWolfy:不,不是。的tr -d '\n'是在XXD的输出,其编码输入的二进制内容作为ASCII十六进制字符(0-9和AF)操作。xxd也会定期输出换行符,以使输出易于阅读,但是在这种情况下,我们希望将其删除。在换行原有的数据将是十六进制形式,并且将不受影响。
善意

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 2011年

COPY BINARY上的PostgreSQL文档(postgresql.org/docs/8.4/interactive/sql-copy.html)指出,在插入二进制数据时需要特殊的文件头。我是否需要构建此标头并将其附加到二进制数据?对于简单地存储二进制数据字符串而言,这似乎有些复杂。
SabreWolfy 2011年

嗯,既然您不确定,我现在就提到它,我只是记得该命令并认为它将执行此操作。也许PL /无论什么方法都是唯一的方法。
盖乌斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.