有将全文字段导入/导出为文件的简单方法吗?
解决了“作为多行加载”的问题。
尝试使用 SQL 的 COPY我只能将全文件转换为全表,而不是单个文本字段,因为 COPY 中的每一行都是原始的。解决回存问题,将完整的 XML 文件保存在文件系统中,不改变二进制表示(保留 SHA1),并且不使用其他外部过程(如 Unix
sed
使用)。
主要问题出在导出,所以这是本页的标题。
PS:往返过程中的“同文件证明”——导入、导出返回并与原文件比较——可以通过sha1sum
演示获得;请参阅下面的示例。所以,一个很自然的需求也是通过SQL来校验同一个SHA1,避免在简单的校验任务上导出。
所有例子
将全文导入到全表(这不是我需要的),
并测试是否可以导出为相同的文本.
PS:我需要将一个文件导入一个字段一行。将完整表格转换为一个文件(这不是我需要的)
并测试是否可以导出为相同文本。
PS:我需要一行(一个字段)到一个文件中。通过SQL计算哈希,字段的SHA1。
比较时必须相同 ...否则这对我来说不是解决方案。
以下示例显示了每个问题和非优雅的解决方法。
<强>1。导入
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);
检查 original 和“back”是否有完全相同的内容:
sha1sum /tmp/test*.*
570b13fb01d38e04ebf7ac1f73dfad0e1d02b027 /tmp/test_back.xml
570b13fb01d38e04ebf7ac1f73dfad0e1d02b027 /tmp/test.xml
PS:看起来很完美,但这里的问题是使用了很多行。真正的导入解决方案可以将文件导入一行(和一个字段)。真正的导出解决方案是一个 SQL 函数,它从单行(单字段)生成 test_back.xml
。
<强>2。将全表转换为一个文件
用它来存储 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
检查,对于 test_back2-bad,不会产生相同的结果。 xml
.
也可以使用外部工具(perl、sed 或任何其他工具)将 \n
转换为 chr(10) perl -p -e 's/\\n/\n/g'/tmp/test_back2-bad.xml >/tmp/test_back2-good.xml
好的,现在 test_back2-good.xml
与原始哈希值相同(在我的示例中为“570b13fb...”)。
使用 Perl 是一种解决方法,没有它怎么办?
<强>3。字段的SHA1
SELECT encode(digest(x::text::bytea, 'sha1'), 'hex') FROM xtmp;
未解决,与原始哈希不同(在我的示例中为“570b13fb...”)...也许 ::text
强制使用 \n< 进行内部表示
符号,因此解决方案将直接转换为 bytea
,但它是无效转换。其他解决方法也不是解决方案,
SELECT encode(digest( replace(x::text,'\n',E'\n')::bytea, 'sha1' ), 'hex')
FROM xtmp
...我尝试使用CREATE TABLE btmp (x bytea)
和COPY btmp FROM '/tmp/test.xml' (FORMAT binary)
,但出现错误("未知的 COPY 文件签名”)。
最佳答案
COPY
不是为此而设计的。它是用来处理表结构的数据的,所以如果没有一些划分行和列的方法,它就无法工作;总会有一些字符 COPY FROM
解释为分隔符,并且 COPY TO
如果它在您的数据中找到一个转义序列,它将插入一些转义序列。如果您正在寻找通用文件 I/O 工具,这不是很好。
事实上,数据库服务器并不是为一般的文件 I/O 而设计的。一方面,任何 直接与服务器文件系统交互的东西都需要 super 用户角色。如果可能的话,您应该像往常一样查询表,并在客户端处理文件 I/O。
也就是说,有几种选择:
- 内置
pg_read_file()
功能,和pg_file_write()
来自adminpack
模块,为文件系统提供最直接的接口(interface),但它们都被限制在集群的数据目录中(我不建议在其中存储随机的用户创建的文件)。 -
lo_import()
andlo_export()
是我所知道的唯一内置函数,它们直接处理文件 I/O 并且可以不受限制地访问服务器的文件系统(在主机操作系统强加的限制内),但是大对象接口(interface)不是特别用户友好.... - 如果您安装了 Perl (
plperlu
) 或 Python (plpythonu
) 等过程语言的不受信任变体,您可以为该语言的 native I/O 例程编写包装函数。 - 通过
COPY TO PROGRAM
没有什么是您无法完成的如果你有足够的决心 - 对于一个人,你可以COPY (SELECT 1) TO PROGRAM 'mv <source_file> <target_file>'
解决pg_file_write()
的限制- 尽管这在某种程度上模糊了 SQL 和外部工具之间的界限(并且继承您的代码库的人可能不会留下深刻印象...)。
关于postgresql - 如何用SQL导出全文文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48327289/