2017-05-01 29 views
0

Postgres 9.6可能使用COPY命令获得on duplicate key UPSERT功能吗?我有一个导入到Postgres的CSV文件,但它可能包含一些重复的密钥违规,所以COPY命令会提供错误,并在遇到错误时终止。将大量行导入到Postgres中,但重复密钥违规

该文件非常大,因此可能无法在应用程序代码中对其进行预处理(以便处理可能导致重复键违规的行),因为所有键都可能不适合内存。

将大量行导入到Postgres中可能包含重复键违规的最佳方式是什么?

+2

副本没有插入。你可以复制到其他表,然后插入不同的 –

+0

@VaoTsun你可以请你的意思吗?我不确定如何实现“插入差异”部分。 – user779159

+0

我做到了。在你的情况下你有UK,所以你必须从'left outer join ...'中插入original.uk_att为null。如果你想插入不同的行(所有列),可以用类似的方式使用'except' –

回答

1

使用扩展名file_fdw,可以打开文件并像查询表一样查询它。

Read more in the documentation.

实施例:

create extension if not exists file_fdw; 

create server csv_server foreign data wrapper file_fdw; 

create foreign table my_csv_file (
    id integer, 
    should_be_unique_id integer, 
    some_other_columns text 
) server csv_server 
options (filename '/data/my_large_file.csv', format 'csv'); 

insert into my_new_table 
select distinct on (should_be_unique_id) * 
from my_csv_file 
order by should_be_unique_id, id desc; 

替代地,如果my_new_table不为空可以使用

insert into my_new_table 
select * 
from my_csv_file 
on conflict ... update ... 
+0

你可以举一个如何使用它的例子吗? – user779159

1

样品:

t=# create table s90(i int primary key, t text); 
CREATE TABLE 
t=# insert into s90 select 1,'a'; 
INSERT 0 1 
t=# copy s90 from stdin delimiter ','; 
Enter data to be copied followed by a newline. 
End with a backslash and a period on a line by itself. 
>> 1,'b' 
>> 2,'c' 
>> \. 
ERROR: duplicate key value violates unique constraint "s90_pkey" 
DETAIL: Key (i)=(1) already exists. 
CONTEXT: COPY s90, line 1 

带副本的解决方法:

t=# create table s91 as select * from s90 where false;; 
SELECT 0 
t=# copy s91 from stdin delimiter ','; 
Enter data to be copied followed by a newline. 
End with a backslash and a period on a line by itself. 
>> 1,'b' 
>> 2,'c' 
>> \. 
COPY 2 
t=# with p as (select s91.* from s91 left outer join s90 on s90.i=s91.i where s90.i is null) 
insert into s90 select * from p; 
INSERT 0 1 
t=# select * from s90; 
i | t 
---+----- 
1 | a 
2 | 'c' 
(2 rows)