我有这样一行csv:
"aaa"|"bbb"|"ccc"|"dddd
eeeee"
我想使用 pgloader (http://pgloader.io/( 或 PostgreSQL COPY (https://www.postgresql.org/docs/9.6/static/sql-copy.html( 导入此数据。我在这里的问题是,根据 CSV 标准,引号字段值中可能会有换行符 ((。但是 pgloader 和 COPY 命令将其视为一行全新的数据,而不是一列内部带有换行符。
COPY schema.table (
col_aaa,
col_bbb,
col_ccc,
col_ddd
)
FROM 'file.csv' WITH DELIMITER '|' ENCODING 'LATIN1' CSV;
我的复制命令我的 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文档和谷歌中搜索了很多。
我唯一发现的是:在双引号字段中解析 的 CSV 文件,但对于超过 100 万行的文件来说,awk 太慢了。
关于如何做到这一点的任何提示?
我更喜欢 pgloader,但我可以接受使用 sed 或 perl 作为正则表达式代理来处理 linux shell 脚本中的文件。
关于如何做到这一点的任何线索?
为了给你一个解决这个问题的想法,我正在写这个例子。
我刚刚假设该文件将仅包含 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"
script.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"
根据需要更改此示例。希望这有帮助。
问题是在行尾有一个\r。为了解决这个问题,我只从数据内部的换行符中删除了\r。
这样pgloader就能够完成这项工作。
我已经通过使用一行perl做到了这一点。
perl -0777 -pi -e 's/(?<="[^"|])*(?<!["|])rn(?=[^"]*")/n/smg' $csv_file_name # O -0777 is explained at em https://stackoverflow.com/questions/9670426/perl-command-line-multi-line-replace
Perl 命令行多行替换