在 PostgreSQL 中使用 COPY FROM 时如何禁用转义?

Tim*_*ith 5 postgresql csv postgresql-9.5

我有一个很大的制表符分隔文件,我想将其读入 PostgreSQL 9.5 中的表。 它包含双引号和反斜杠,我想将它们视为常规字符。

我认为 COPY FROM 是要走的路,但我不知道如何禁用转义。

以下是数据示例(来自Google 的 ngram 数据集):

aX13_X  2006    8   5
aX13_X  2007    4   3
aX13_X  2008    2   1
a\  1852    1   1
a\  1935    1   1
a\  1937    2   2
ACT1V1T1ES  2003    15  11
ACT1V1T1ES  2004    63  6
ACT1V1T1ES  2005    1   1
ACT1V1T1ES  2006    5   4
ACT1V1T1ES  2008    4   3
ACTION="    1995    3   3
ACTION="    1996    6   5
ACTION="    1997    9   7
ACTION="    1998    19  11
ACTION="    1999    11  5
Run Code Online (Sandbox Code Playgroud)

和表:

CREATE TABLE onegram (
    id SERIAL,
    ngram character text,
    year integer NOT NULL,
    match_count integer NOT NULL,
    volume_count integer NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

如果我尝试不使用修饰符,反斜杠会转义选项卡:

ngram=# copy onegram (ngram, year, match_count, volume_count)
from '/home/tims/data/ngram/test.tsv';
ERROR:  missing data for column "volume_count"
CONTEXT:  COPY onegram, line 4: "a\     1852    1       1"
Run Code Online (Sandbox Code Playgroud)

所以我切换到 CSV,然后双引号字符引用制表符:

ngram=# copy onegram (ngram, year, match_count, volume_count)
from '/home/tims/data/ngram/test.tsv' WITH CSV DELIMITER E'\t';
ERROR:  unterminated CSV quoted field
CONTEXT:  COPY onegram, line 17: "ACTION="      1999    11      5
"
Run Code Online (Sandbox Code Playgroud)

使用 CSV 可以让我使用 DELIMITER 关键字。如果我选择样本中没有出现的分隔符(在这种情况下为空格),它会起作用:

ngram=# copy onegram (ngram, year, match_count, volume_count)
from '/home/tims/data/ngram/test.tsv' WITH CSV DELIMITER E'\t' QUOTE E' ';
COPY 16
Run Code Online (Sandbox Code Playgroud)

但我希望能够包含任何字符(制表符和换行符除外)。 那么,如何禁用 QUOTE?或者我可以用什么来代替 COPY FROM?

编辑:出于稍微随意的原因,理想情况下我想要一个不涉及预处理数据的选项。

Abe*_*sto 5

copy命令默认使用texttab分隔符的格式。所以你只需要做一件事就是逃避反斜杠:

copy onegram (ngram, year, match_count, volume_count)
from program 'sed ''s/\\/\\\\/g'' < /home/tims/data/ngram/test.tsv';
select * from onegram;
???????????????????????????????????????????????????????
? id ?   ngram    ? year ? match_count ? volume_count ?
???????????????????????????????????????????????????????
?  1 ? aX13_X     ? 2006 ?           8 ?            5 ?
?  2 ? aX13_X     ? 2007 ?           4 ?            3 ?
?  3 ? aX13_X     ? 2008 ?           2 ?            1 ?
?  4 ? a\         ? 1852 ?           1 ?            1 ?
?  5 ? a\         ? 1935 ?           1 ?            1 ?
?  6 ? a\         ? 1937 ?           2 ?            2 ?
?  7 ? ACT1V1T1ES ? 2003 ?          15 ?           11 ?
?  8 ? ACT1V1T1ES ? 2004 ?          63 ?            6 ?
?  9 ? ACT1V1T1ES ? 2005 ?           1 ?            1 ?
? 10 ? ACT1V1T1ES ? 2006 ?           5 ?            4 ?
? 11 ? ACT1V1T1ES ? 2008 ?           4 ?            3 ?
? 12 ? ACTION="   ? 1995 ?           3 ?            3 ?
? 13 ? ACTION="   ? 1996 ?           6 ?            5 ?
? 14 ? ACTION="   ? 1997 ?           9 ?            7 ?
? 15 ? ACTION="   ? 1998 ?          19 ?           11 ?
? 16 ? ACTION="   ? 1999 ?          11 ?            5 ?
???????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)


Cra*_*ger 3

看来您需要预处理数据。COPY如果您想允许任何可能的输入,则无法摄取此数据。它不是有效的 CSV,也不遵循 postgres 类似 TSV 的本机 COPY 格式的规则。没有可以设置的选项QUOTE NONE或类似的东西。

我建议使用类似 perl/python 脚本来转换数据,您可以使用COPY ... FROM PROGRAM. 或者通过管道将数据传输到psql客户端输入,或者通过转换数据并通过客户端驱动程序(如DBD::Pg或 )直接将其提供给 Postgres psycopg2,这两种方法都COPY支持。

你总是可以提交一个 postgres 补丁,这样下一个人就可以更轻松地解决同样的问题。