防止 LOAD DATA INFILE 转义双引号

Prevent LOAD DATA INFILE from escaping double double quotes

我有如下的 csv 数据:

"E12 98003";1085894;"HELLA";"8GS007949261";"";1
"5 3/4"";652493;"HELLA";"9HD140976001";"";1

一些字段包含在双引号中。问题是 正如您在第二行中看到的那样,第一列中的数据在末尾包含一个双引号作为数据的一部分。

我尝试了以下方法:

LOAD DATA INFILE file.csv
INTO TABLE mytable
FIELDS TERMINATED BY ';' ENCLOSED BY '"'
LINES TERMINATED BY '\r\n'

但它会使用数据中的引号来转义包含引号的字段。我也尝试了 ESCAPED BY ''ESCAPED BY '\' 但没有成功。 有没有办法阻止 LOAD DATA INFILE 命令转义双引号? 或者我应该解析 csv 并在只有一个时加双引号吗? 无论如何,我正在使用 powershell 将编码更改为 utf8 来解析文件。有什么办法可以快速解决这个问题吗?我的 powershell 代码:

function Convert-FileToUTF8 {

    param([string]$infile,
          [string]$outfile,
          [System.Int32]$encodingCode)

    $encoding = [System.Text.Encoding]::GetEncoding($encodingCode)
    $text = [System.IO.File]::ReadAllText($infile, $encoding)
    [System.IO.File]::WriteAllText($outfile, $text)

}

好的,我使用 .NET 正则表达式修复了 csv。这是昂贵的,但不是太多。 我写了

$text = [regex]::Replace($text, "(?m)(?<!^)(?<!\;)""(?!\;)(?!\r?$)", '""');

就在函数的最后一行之前,它似乎工作正常。由于我是正则表达式的新手,这可能会得到改进。

主要问题是输入数据构成了无效的 CSV 语法,如 RFC-4180 第 7 段所述:

If double-quotes are used to enclose fields, then a double-quote appearing inside a field must be escaped by preceding it with another double quote.

但是在您的 PowerShell 脚本中,您可以尝试使用额外的一行来解决此问题,使用 $text 上的 replace method,一旦您获得它的价值:

$text = $text.Replace('"";', '""";')

这应该足够了,因为加载程序可以很好地处理出现在数据其他地方的未转义双引号,如 mysql.com(我的重点)所述:

If the field begins with the ENCLOSED BY character, instances of that character are recognized as terminating a field value only if followed by the field or line TERMINATED BY sequence.

当然,如果格式错误的CSV中有包含";的数据,那你还是有问题。但是很难确定这种情况是终止数据还是应该被视为数据的一部分,即使对于人类也是如此:-)

mysql.com 上发现的另一件需要注意的事情:

If the input values are not necessarily enclosed within quotation marks, use OPTIONALLY before the ENCLOSED BY keywords.

此外:在使用 ENCLOSED BY 选项时,在 MySQL 中导入值包含在引号中的 CSV 文件工作正常。除非包含的字段是一行中的最后一个字段,并且您使用了 Excel 创建 CSV 文件。 Excel 省略一行中最后一个字段之后的字段分隔符。 MySQL 不介意...除非最后一个字段用引号引起来。然后导入在该行终止。

示例:
这很好用: ...;value2;value3(没有尾随分隔符)
这也很好用...;"value 2";value3(引号括起来的值)
这也很好用...;value 2;"value3"; (最后一个字段值用引号和尾随分隔符括起来)
但这会破坏导入:...;value2;"value 3"(最后一个字段值用引号引起来并且没有尾随分隔符)

我花了一些时间才弄明白;希望分享这个可以节省其他人的时间。