1

我有这样的 csv 行:

"aaa"|"bbb"|"ccc"|"dddd
eeeee"

我想使用 pgloader ( http://pgloader.io/ ) 或 PostgreSQL COPY ( https://www.postgresql.org/docs/9.6/static/sql-copy.html ) 导入这些数据。我的问题是,根据 CSV 标准,在引用的字段值内可能有换行符 (\n)。但是 pgloader 和 COPY 命令将其视为全新的数据行,而不是其中包含换行符的一列。

COPY schema.table (
    col_aaa,
    col_bbb,
    col_ccc,
    col_ddd
) 
    FROM 'file.csv' WITH DELIMITER '|' ENCODING 'LATIN1' CSV;

我的 COPY 命令 我的 pgloader 命令

LOAD CSV
FROM 'file.csv' 
INTO postgresql://user:password@host:5432/database?schema.table (col_aaa, col_bbb, col_ccc, col_ddd)

WITH   
skip header = 0,
fields optionally enclosed by '"',
fields escaped by double-quote,
fields terminated by '|'  

SET client_encoding to 'latin1'
BEFORE LOAD DO
    $$ TRUNCATE anac.aerodromos_csv RESTART IDENTITY; $$;

我从 PostgreSQL 文档和谷歌搜索了很多。

我发现的唯一一件事是:Parsing CSV file with \n in double quotes fields but awk is too slow for a file with more than 100万行。

关于如何做的任何提示?

我的首选是 pgloader,但我可以接受使用 sed 或 perl 作为正则表达式代理来处理 linux shell 脚本中的文件。

关于如何做的任何线索?

4

2 回答 2

0

问题是在行尾有一个\r\n。为了解决这个问题,我只从数据内的换行符中删除了 \r 。

这样 pgloader 就能够完成这项工作。

我已经通过使用单行 perl 来做到这一点。

perl -0777 -pi -e 's/(?<="[^"|])*(?<!["|])\r\n(?=[^"]*")/\n/smg' $csv_file_name # O -0777 is explained at em https://stackoverflow.com/questions/9670426/perl-command-line-multi-line-replace

Perl 命令行多行替换

于 2017-06-21T19:49:33.430 回答
0

为了给你一个解决这个问题的想法,我正在写这个例子。

我刚刚假设该文件将仅包含 4 列,并且仅包含 1 个换行符。如果不是这种情况,那么您需要更改此设置。

输入文件:

"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"dddd
eeeee"
"aaa"|"bbb"|"cc
c"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"b
bb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"a
aa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"dddd
eeeee"

脚本.pl

#!/usr/bin/perl
use strict; use warnings; use Data::Dumper;

open ( my $RFH, '<', 'input.io' ) or die ($!);
open ( my $WFH, '>', 'output.o' ) or die ($!);

my $line_break = 0;
my $old_line = '';

while ( my $line = <$RFH> ) {
    chomp($line);
    if ( ! $line_break ){
        my @columns = split( /\|/, $line );
        if ( scalar( @columns ) == 4 && $columns[3] =~ m/"$/ ){
            print $WFH $line."\n";
        }
        else{
            $line_break = 1;
            $old_line = $line;
            next;
        }
    }
    else{
        $line = $old_line . $line;
        $old_line = '';
        $line_break = 0;
        print $WFH $line."\n";
    }
}

close($RFH);
close($WFH);

输出文件:

"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"
"aaa"|"bbb"|"ccc"|"ddddeeeee"

根据您的需要更改此示例。希望这可以帮助。

于 2017-06-08T07:27:26.513 回答