如何使用SQL导出全文文件?

时间:2018-01-18 17:40:46

标签: postgresql export

有一种简单的方法可以将全文字段导入/导出为文件吗?

  • 解决了“以多行加载”的问题。
    尝试使用SQL COPY我只能将完整文件转换为全表,而不是单个文本字段,因为COPY中的每一行都是原始的。

  • 解决了保存问题,将完整的XML文件保存在文件系统中,无需更改旁路表示(保留SHA1 ),也没有其他exernal过程(如Unix { {1}}使用)。

主要问题在于导出,因此这是此页面的标题。

PS:往返的“同一文件证明” - 导入,导出和原始比较 - 可以通过sed演示获得;见下面的例子。因此,自然需求也是通过SQL检查相同的SHA1,避免在简单的检查任务上导出。

所有示例

  1. 将全文导入全表(不是我需要的),并测试导出为相同的文本。
    PS:我需要将一个文件导入一个字段和一行。

  2. 完整表格转换为一个文件(不是我需要的)和测试导出为相同的文本。
    PS:我需要一行(一个字段)到一个文件中。

  3. 按SQL计算哈希值,字段的SHA1
    比较时必须相同 ...这对我来说不是解决方案。

  4. 以下示例显示了每个问题和非优雅的解决方法。

    1。导入

    sha1sum

    检查原件和“背面”是否具有完全相同的内容:

    CREATE TABLE ttmp (x text);
    COPY ttmp FROM '/tmp/test.xml' ( FORMAT text ); -- breaking lines lines
    COPY (SELECT x FROM ttmp) TO '/tmp/test_back.xml' (format TEXT);
    
    PS:看起来很完美,但这里的问题是使用了很多行。真正的导入解决方案可以将文件导入一行(和一个字段)。真正的导出解决方案是一个SQL函数,它从一行(单个字段)生成sha1sum /tmp/test*.* 570b13fb01d38e04ebf7ac1f73dfad0e1d02b027 /tmp/test_back.xml 570b13fb01d38e04ebf7ac1f73dfad0e1d02b027 /tmp/test.xml

    2。将整个表格转换为一个文件

    用它来存储XML:

    test_back.xml

    ...但不行,因为我们可以CREATE TABLE xtmp (x xml); INSERT INTO xtmp (x) SELECT array_to_string(array_agg(x),E'\n')::xml FROM ttmp ; COPY (select x::text from xtmp) TO '/tmp/test_back2-bad.xml' ( FORMAT text ); 检查,不会为sha1sum /tmp/test*.xml生成相同的结果

    使用外部工具(perl,sed或任何其他工具)进行从test_back2-bad.xml到chr(10)的翻译。\n

    好的,现在perl -p -e 's/\\n/\n/g' /tmp/test_back2-bad.xml > /tmp/test_back2-good.xml具有相同的哈希值(在我的例子中为“570b13fb ...”)。 使用Perl是一种解决方法,没有它怎么办?

    第3。字段的SHA1

    test_back2-good.xml

    没有解决,是不是相同的hash tham原文(在我的例子中是“570b13fb ...”)...也许是SELECT encode(digest(x::text::bytea, 'sha1'), 'hex') FROM xtmp; 强制使用::text符号的内部表示,所以解决方案将直接转换为\n,但它是无效的演员。另一种解决方法也不是解决方案,

    bytea

    ...我尝试SELECT encode(digest( replace(x::text,'\n',E'\n')::bytea, 'sha1' ), 'hex') FROM xtmp CREATE TABLE btmp (x bytea),但错误(“未知的COPY文件签名”)。

2 个答案:

答案 0 :(得分:2)

COPY并未针对此进行设计。它意味着处理表结构化数据,因此它无法在某种程度上划分行和列;总会有一些COPY FROM解释为分隔符的字符,如果在数据中找到一个转义序列,COPY TO将插入一些转义序列。如果您正在寻找通用文件I / O工具,这并不是很好。

实际上,数据库服务器并不是针对通用文件I / O而设计的。首先,与服务器文件系统直接交互的任何将需要超级用户角色。如果可能的话,你应该像往常一样查询表,并在客户端处理文件I / O.

尽管如此,还是有一些选择:

  • 内置pg_read_file()功能和adminpack模块中的pg_file_write()提供了与文件系统最直接的界面,但它们都限制在群集和#39;的数据目录(我不建议在其中存储随机用户创建的文件)。
  • lo_import() and lo_export()是我所知道的唯一内置函数,它直接处理文件I / O,并且可以不受限制地访问服务器的文件系统(在主机操作系统强加的限制范围内) ,但是大对象界面不是特别用户友好....
  • 如果安装过程语言(如Perl(plperlu)或Python(plpythonu)的不受信任的变体,则可以为该语言的本机I / O例程编写包装函数。
  • 如果你已经足够的确定,那么你无法通过COPY TO PROGRAM完成任务 - 例如,你可以COPY (SELECT 1) TO PROGRAM 'mv <source_file> <target_file>'解决{pg_file_write()的限制1}} - 虽然这在某种程度上模糊了SQL和外部工具之间的界限(任何继承你的代码库的人都不会留下深刻的印象......)。

答案 1 :(得分:1)

您可以在postgres函数中使用plpythonu f.open(),f.write(),f.close()来写入文件。

需要安装语言扩展名。

https://www.postgresql.org/docs/8.3/static/plpython.html

邮件列表中的工作示例。 https://www.postgresql.org/message-id/flat/20041106125209.55697.qmail%40web51806.mail.yahoo.com#20041106125209.55697.qmail@web51806.mail.yahoo.com

  

例如plpythonu

CREATE FUNCTION makefile(p_file text, p_content text) RETURNS text AS $$
  o=open(args[0],"w")
  o.write(args[1])
  o.close()
  return "ok"
$$ LANGUAGE PLpythonU;

PS:为安全实施,请参阅this example

准备

使用 PLpython 扩展名有一个不那么明显的过程。假设一个UBUNTU服务器:

  1. 在SQL上检查SELECT version()
  2. 终端检查sudo apt install postgresql-plpython列出的版本。
  3. 安装正确的版本,例如。 sudo apt install postgresql-plpython-9.6
  4. 返回SQL执行CREATE EXTENSION plpythonu
  5. 测试

    /tmp是默认设置,用于创建或使用其他文件夹,例如。 /tmp/sandbox,使用sudo chown postgres.postgres /tmp/sandbox

    假设问题示例的表格。 SQL脚本,重复一些行:

      DROP TABLE IF EXISTS ttmp; 
      DROP TABLE IF EXISTS xtmp; 
    
      CREATE TABLE ttmp (x text);
      COPY ttmp FROM '/tmp/sandbox/original.xml' ( FORMAT text );
      COPY (SELECT x FROM ttmp) TO '/tmp/sandbox/test1-good.xml' (format TEXT);
    
      CREATE TABLE xtmp (x xml);
      INSERT INTO  xtmp (x) 
         SELECT array_to_string(array_agg(x),E'\n')::xml FROM ttmp
      ;
    
      COPY (select x::text from xtmp) 
      TO '/tmp/sandbox/test2-bad.xml' ( FORMAT text );
    
      SELECT makefile('/tmp/sandbox/test3-good.xml',x::text) FROM xtmp;
    

    我的XML原始文件的sha1sum *.xml输出:

    4947..  original.xml
    4947..  test1-good.xml
    949f..  test2-bad.xml
    4947..  test3-good.xml