csv 解决“错误:在Postgres的数据”“中找到文本换行符?

4smxwvx5  于 2023-01-10  发布在  其他
关注(0)|答案(5)|浏览(326)

我有一个包含3200万个元组的数据集,我正在使用COPY FROM将这些元组复制到表中。在前700万个元组中,有3个格式不正确。在这些情况下,下一个记录不是在当前记录下面,而是追加到同一行上当前记录的末尾。因此,

record1
record2

它是

record1record2

我通过导航到应该换行的地方并在每个示例中按一次"Enter"键(典型的换行符输入)来修复这个问题。一旦我修复了这些行,COPY函数就可以完全正确地读取它们。对我来说,这意味着"Enter"是插入换行符的有效方法,因为COPY函数可以毫无问题地读取那些"Enter"生成的换行符。
然而,后来当我通过第700万个元组时,我遇到了:

ERROR: literal newline found in data
HINT: Use "\n" to represent newline.
Context: COPY time_raw, line 7308000

SQL状态:22P04
我查看了该记录的数据,发现它与其上或其下的记录没有什么不同。为了确定这一点,我在记录7308000的开头按了"Backspace"键,将其上移一行到记录7307999的结尾。就像上面的格式record1record2一样。然后我按了"Enter"以确保开始记录7308000的换行符将与COPY先前毫不费力地接受的字符相同。结束记录7307999的换行符与我用来分隔早期格式不正确的记录的换行符完全相同(再一次,COPY没有问题地加入了这个换行符)。为了覆盖我的基础,我对记录7308001做了同样的操作,确保结束记录7308000的新行与我之前输入的新行相同,COPY接受此操作。但是,在保存并尝试再次从文件复制时,我得到:

ERROR: literal newline found in data
HINT: Use "\n" to represent newline.
Context: COPY time_raw, line 7307999

很明显,错误上移了,COPY之前接收的换行符突然变得无效。我再次查看数据,将7307999的开头移到7307998的结尾,然后按"Enter"键插入一个换行符,COPY一直认为该字符对700多万条记录有效。因此,此时,我确信7307998的结尾是一个换行符,应该已经证明了它在COPY中是有效的。我再次运行查询,现在我得到:

ERROR: literal newline found in data
HINT: Use "\n" to represent newline.
Context: COPY time_raw, line 7307998

错误又上升了。据我所知,我只是放入了和我之前做的相同的"输入"新行字符,由于某种原因,过去的7308000副本将它们读为无效。
这些是数据集的第7307996 - 7308000行(56列,大部分无意义)

2012-02-23T13:10:03.1769237+00:00   9863996 12604   13807   8171    0000    0001    0000    0000    0000    0000    0000    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1   1   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
2012-02-23T13:10:03.1869189+00:00   9863997 12604   13807   8171    0000    0001    0000    0000    0000    0000    0000    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1   1   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
2012-02-23T13:10:03.1969230+00:00   9863998 12604   13807   8171    0000    0001    0000    0000    0000    0000    0000    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1   1   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
2012-02-23T13:10:03.2069124+00:00   9863999 12604   13807   8171    0000    0001    0000    0000    0000    0000    0000    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1   1   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0
2012-02-23T13:10:03.2169261+00:00   9864000 12604   13807   8171    0000    0001    0000    0000    0000    0000    0000    0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1   1   1   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

我在stackoverflow编辑器中的每条记录后添加了一个"Enter",以便一条接一条地显示它们,但关键是相关的中间行(7307998)的格式与其他文件完全相同,并且我确保它被换行符包围,这些换行符已经被COPY函数显示为有效字符。每当我试图确保记录周围的换行符与我之前使用的换行符相同时,错误就会向上移动一行,我不知道在这种情况下该怎么办。
我的疑问是:

copy time_raw from E'C:\\Users\\bozon92\\Documents\\YorkU\\Summer 2016\\4080 Project\\Other Files\\allData.txt';

我试过将"with(format csv,delimiter '\t')"附加到后面,但这告诉我COPY delimiter必须是一个单字节字符,而"with(format csv,delimiter'')"(''是一个文本制表符空格,而不是\t)给我带来了相同性质的错误,只是语法略有不同:

ERROR:  unquoted newline found in data
HINT:  Use quoted CSV field to represent newline.
CONTEXT:  COPY time_raw, line 7307998

只是"未引用"而不是"字面"。
作为说明,我已经被告知我可以只将数据削减到700万个元组,我可能最终会这样做,但我想知道为什么会发生这个问题,这样我就可以在未来避免它。我不知道数据有什么问题,因为那些特定的记录看起来完全正常,格式与它之前和之后的记录完全相同,那么,我该如何处理这个文字换行符问题呢?我不知道该如何处理,因为我甚至找不到错误的痕迹。

ukdjmx9f

ukdjmx9f1#

根据PostgreSQL源代码片段copy.c

/* Process \n */
 if (c == '\n' && (!cstate->csv_mode || !in_quote))
 {
     if (cstate->eol_type == EOL_CR || cstate->eol_type == EOL_CRNL)
         ereport(ERROR,
             (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
             !cstate->csv_mode ?
             errmsg("literal newline found in data") :
             errmsg("unquoted newline found in data"),
             !cstate->csv_mode ?
             errhint("Use \"\\n\" to represent newline.") :
             errhint("Use quoted CSV field to represent newline.")));
      cstate->eol_type = EOL_NL;      /* in case not set yet */
      /* If reach here, we have found the line terminator */
      break;
}

这意味着你的输入数据在你的字符串中的某个地方使用了字节0x0A,例如你使用了"abcNxyz",而不是N,实际上有一个值为0x0A的字节。
解决方法是使用字符串"abc\n",你应该能够找到所有虚假的换行符,并使用一些脚本(可能是Python或Perl)将它们替换为\n

kyvafyod

kyvafyod2#

如果您有权访问提取元组的源系统,则可以选择在提取数据时替换所有换行符:

SELECT regexp_replace(input_field, '[\\n\\r]+', ' ')

这将用一个空格代替行尾字符。这为我的情况修复了ERROR: literal newline found in data

xiozqbni

xiozqbni3#

您要导入的转储文件可能以\r (0x0D)结尾,而不是\r\n (0x0D 0x0A),从而导致这个错误,这是我遇到的情况。

ktca8awb

ktca8awb4#

使用ATOM或类似的文本编辑器,使用Regex搜索并将[\r\n]+替换为\n。尽管它可能会因超过1M行而锁定。

cig3rfwq

cig3rfwq5#

在Linux中,我用这三个命令解决了

  • sed -i的///g文件名
  • sed -i -e的/\r//g文件名
  • sed -i的/\x00//g'文件名

相关问题