【问题标题】:ERROR: COPY delimiter must be a single one-byte character错误:COPY 分隔符必须是单个单字节字符
【发布时间】:2017-04-10 03:03:55
【问题描述】:

我想将带有分隔符“~,~”的平面文件中的数据加载到 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


    【解决方案1】:

    如果你使用Vertica,你可以使用E'\t'或U&'\0009'

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

    【讨论】:

      【解决方案2】:

      不幸的是,没有办法在 Postgres 中加载带有多个字符分隔符 ~,~ 的平面文件,除非您想以某种(极好的)方式自己修改 source code(当然还要重新编译):

      /* 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
      

      【讨论】:

      • 有什么方法可以将转义字符或垂直制表符表示为单字节字符并将它们中的任何一个用作分隔符吗?
      • 我不确定我是否理解您的问题。你可以写例如DELIMITER E'\x3A' 用于 : ASCII 十六进制表示,E'\xB' 用于垂直制表符 (VT) 字符。
      【解决方案3】:

      显而易见的是,所有其他答案都建议这样做。编辑导入文件。我也会那样做。

      但是,作为概念证明,这里有两种方法可以在无需额外工具的情况下完成此操作

      1) 一般解决方案

      CREATE OR REPLACE FUNCTION f_import_file(OUT my_count integer)
        RETURNS integer AS
      $BODY$
      DECLARE
          myfile    text;  -- read xml file into that var.
          datafile text := '\path\to\file.txt'; -- !pg_read_file only accepts relative path in database dir!
      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, you might need additional quotes to create a valid format.
      
      GET DIAGNOSTICS my_count = ROW_COUNT;
      
      END;
      $BODY$
        LANGUAGE plpgsql VOLATILE;
      

      这使用了许多非常高级的功能。如果有人真正感兴趣并需要解释,请在这篇文章中发表评论,我会详细说明。

      2) 特殊情况

      如果您可以保证 '~' 仅出现在分隔符 '~,~' 中,那么在这种特殊情况下您可以继续使用普通的 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 '~';
      
      ALTER TABLE foo_tmp DROP COLUMN tmp1;
      ALTER TABLE foo_tmp DROP COLUMN tmp2;
      
      INSERT INTO foo SELECT * FROM foo_tmp;
      

      【讨论】:

        【解决方案4】:

        不太确定您是在寻找 postgresql 解决方案还是只是一般的解决方案。

        如果是我,我会打开一份 vim(或 gvim)并运行推荐 :%s/~,~/~/g
        用“~”替换所有“~,~”。

        【讨论】:

        • hmm..我正在寻找 postgresql 解决方案。
        • 如果你用谷歌搜索,你会发现这是一个已知的限制,没有好的解决方法。
        【解决方案5】:

        您可以使用单个字符分隔符,打开notepadctrl+h 替换~,~ 用不会干扰的东西。喜欢|

        【讨论】:

        • 不,我的应用程序将数据保存在带有~,~ 分隔符的平面文件中,我们无法更改该行为。我们的一个数据提取作业将此文件加载到 postgresql 表中。所以,请停止建议替代解决方案。如果 PostgreSQL 中的复制语句不允许使用多个字符作为分隔符,有没有办法像 oracle 的 SQLLoader 一样加载数据。
        • 为什么不能复制文件.. 而不是替换.. 然后使用 COPY 加载
        猜你喜欢
        • 2023-04-03
        • 1970-01-01
        • 2021-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-21
        相关资源
        最近更新 更多