有一种简单的方法可以将全文字段导入/导出为文件吗?
解决了“以多行加载”的问题。
尝试使用SQL COPY我只能将完整文件转换为全表,而不是单个文本字段,因为COPY中的每一行都是原始的。
解决了保存问题,将完整的XML文件保存在文件系统中,无需更改旁路表示(保留SHA1 ),也没有其他exernal过程(如Unix { {1}}使用)。
主要问题在于导出,因此这是此页面的标题。
PS:往返的“同一文件证明” - 导入,导出和原始比较 - 可以通过sed
演示获得;见下面的例子。因此,自然需求也是通过SQL检查相同的SHA1,避免在简单的检查任务上导出。
将全文导入全表(不是我需要的),并测试导出为相同的文本。
PS:我需要将一个文件导入一个字段和一行。
将完整表格转换为一个文件(不是我需要的)和测试导出为相同的文本。
PS:我需要一行(一个字段)到一个文件中。
按SQL计算哈希值,字段的SHA1 。
比较时必须相同 ...这对我来说不是解决方案。
以下示例显示了每个问题和非优雅的解决方法。
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文件签名”)。
答案 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,并且可以不受限制地访问服务器的文件系统(在主机操作系统强加的限制范围内) ,但是大对象界面不是特别用户友好.... 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
例如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服务器:
SELECT version()
。sudo apt install postgresql-plpython
列出的版本。sudo apt install postgresql-plpython-9.6
。CREATE EXTENSION plpythonu
。 /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