我正在尝试在我的项目中实现数据库抽象,但现在我不得不在PostgreSQL中进行批量INSERT。我的项目在C#中,我使用的是PostgreSQL 9.3和npgsql.dll 2.0.14。
对于Microsoft SQL Server,我只是通过连接所有语句然后执行ExecuteNonQuery来进行批量INSERT:
IF NOT EXISTS (SELECT id FROM table WHERE id = 1) INSERT INTO table (id) VALUES (1);
IF NOT EXISTS (SELECT id FROM table WHERE id = 2) INSERT INTO table (id) VALUES (2);
IF NOT EXISTS (SELECT id FROM table WHERE id = 3) INSERT INTO table (id) VALUES (3);
尽管可以通过SELECT-WHERE在PostgreSQL中替换IF-NOT-EXISTS子句,但遗憾的是这种方法仍然不起作用 - 因为PostgreSQL中的每个语句都是单独提交的。
所以我搜索了另一个解决方案,并找到了使用COPY
命令和NpgsqlCopySerializer / NpgsqlCopyIn以便按顺序“流式传输”批量数据的方法。但是现在我总是遇到主键违规错误 - 因为EXISTS / WHERE子句似乎不能与COPY
语句一起使用。
我真的想避免一个一个地进行INSERT,因为这会极大地减慢我的应用程序,所以我希望任何人都已经解决了这个问题!
答案 0 :(得分:1)
通常对于这种情况,我有一个单独的临时表没有PK约束,我使用COPY
填充它(假设数据的格式对它有意义)做一个COPY
)。然后我会做类似的事情:
insert into table
select a.*
from staging a
where not exists (select 1
from table
where a.id = b.id)
这种方法与原始设计相差无几。
我并不完全理解你的问题的这一部分,但这似乎与你的问题无关:
不幸的是,这种方法仍然不起作用 - 因为每一个 postgreSQL中的语句是单独提交的。
这根本不是真的,不适用于任何RDBMS。当然,可能在您的客户端上启用了自动提交,但这并不意味着postgres会单独提交每个语句,并且您无法禁用自动提交。这种方法可行:
begin;
insert into table (id) select 1 where not exists (select 1 from table where id = 1);
insert into table (id) select 2 where not exists (select 1 from table where id = 2);
insert into table (id) select 3 where not exists (select 1 from table where id = 3);
commit;
然而,正如您所指出的,如果您有多个此类陈述,您很快就会遇到一些性能问题。