错误:复制分隔符必须是单个一字节字符

问题描述 投票:0回答:5

我想将带有分隔符“~,~”的平面文件中的数据加载到 PostgreSQL 表中。我已经尝试如下,但看起来分隔符有限制。如果 COPY 语句不允许使用多个字符作为分隔符,是否有其他方法可以做到这一点?

metadb=# \COPY public.CME_DATA_STAGE_TRANS FROM 'E:\Infor\Outbound_Marketing\7.2.1\EM\metadata\pgtrans.log' WITH      DELIMITER AS '~,~'
ERROR:  COPY delimiter must be a single one-byte character
\copy: ERROR:  COPY delimiter must be a single one-byte character
postgresql postgresql-copy
5个回答
16
投票

如果您使用 Vertica,您可以使用 E' ' 或 U&' 9'

要指示非打印分隔符(例如制表符), 指定扩展字符串语法中的字符 (E'...')。如果你的 数据库已启用 StandardConformingStrings,请使用 Unicode 字符串 文字 (U&'...')。例如,使用 E' ' 或 U&' 9' 来 指定制表符作为分隔符。


5
投票

显而易见的事情就是所有其他答案所建议的。编辑导入文件。我也会这么做。

但是,作为概念证明,这里有两种方法可以实现此目的无需额外工具

通用解决方案

这利用了

pg_read_file()
,默认情况下仅限于 超级用户。 (但请阅读手册。)

CREATE OR REPLACE FUNCTION f_import_file(OUT my_count integer)
  RETURNS integer
  LANGUAGE plpgsql VOLATILE AS
$func$
DECLARE
   myfile   text;  -- read xml file into that var.
   -- !pg_read_file() only accepts relative path based on database dir!
   datafile text := '\path\to\file.txt';
BEGIN
   myfile := pg_read_file(datafile, 0, 100000000);  -- arbitrary 100 MB max.

   INSERT INTO public.my_tbl
   SELECT ('(' || regexp_split_to_table(replace(myfile, '~,~', ','), E'\n') || ')')::public.my_tbl;

   -- !depending on file format, additional quotes may be needed to create a valid format.

   GET DIAGNOSTICS my_count = ROW_COUNT;
END
$func$;

这使用了许多高级功能。

特殊情况

如果您可以保证“~”仅出现在分隔符“~,~”中,那么在这种特殊情况下您可以继续使用普通的

COPY
。只需将“~,~”中的“,”视为附加列,然后批量加载到与之匹配的临时表即可。
比如说,你的桌子看起来像这样:

CREATE TABLE foo (a int, b int, c int);

然后您可以(在一笔交易中):

CREATE TEMP TABLE foo_tmp ON COMMIT DROP (
  a int, tmp1 "char"
, b int, tmp2 "char"
, c int);

COPY foo_tmp FROM '\path\to\file.txt' WITH DELIMITER AS '~';

INSERT INTO foo (a,b,c)
SELECT a,b,c FROM foo_tmp;

4
投票

不幸的是,没有办法在 Postgres 中加载带有多个字符分隔符

~,~
的平面文件,除非你想以某种(很棒的)方式自己修改源代码(当然还要重新编译):

/* Only single-byte delimiter strings are supported. */
if (strlen(cstate->delim) != 1)
    ereport(ERROR,
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    errmsg("COPY delimiter must be a single one-byte character")));

你想要的是使用一些外部工具预处理你的输入文件,例如

sed
可能是GNU/Linux平台上的最佳伴侣,例如:

sed s/~,~/\\t/g inputFile

1
投票

不太确定您是在寻找 postgresql 解决方案还是只是通用解决方案。

如果是我,我会打开一份 vim(或 gvim)并运行命令

:%s/~,~/~/g

这会将所有“~,~”替换为“~”。


0
投票

您可以使用单个字符分隔符,打开

notepad
ctrl+h
~,~
替换为不会干扰的内容。就像
|

© www.soinside.com 2019 - 2024. All rights reserved.