What happens with duplicates when inserting multiple rows?
我正在运行一个python脚本,它将大量数据插入Postgres数据库,我使用一个查询来执行多行插入:
1 | INSERT INTO TABLE (col1,col2) VALUES ('v1','v2'),('v3','v4') ... etc |
我想知道如果它碰到插入的重复键会发生什么。它会停止整个查询并引发异常吗?或者它只是忽略了特定行的插入并继续?
假设
通常,如果违反了任何约束,则会引发一个异常(除非被困在过程服务器端语言(如plpgsql)中),该异常不仅会回滚语句,还会回滚整个事务。
没有并发写入即:没有其他事务会试图同时写入同一个表。
排除使用
WHERE NOT EXISTS ... 或任何其他适用技术的表中已有的行:- 选择其他表中不存在的行
也不要忘记删除插入集内的重复项,半反连接
WHERE NOT EXISTS ... 不会排除这些重复项。
一种同时处理这两个问题的方法是
1 2 3 4 5 6 | INSERT INTO tbl (col1, col2) VALUES (text 'v1', text 'v2') -- explicit type cast may be needed in 1st row , ('v3', 'v4') , ('v3', 'v4') -- beware of dupes in source EXCEPT SELECT col1, col2 FROM tbl; |
没有关键字
- 在PostgreSQL中使用except子句
一般来说,如果目标表很大,那么源上的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | INSERT INTO tbl (col1, col2) SELECT * FROM ( SELECT DISTINCT * FROM ( VALUES (text 'v1', text'v2') , ('v3', 'v4') , ('v3', 'v4') -- dupes in source ) t(c1, c2) ) t WHERE NOT EXISTS ( SELECT 1 FROM tbl WHERE col1 = t.c1 AND col2 = t.c2 ); |
如果有很多重复的话,首先将它们折叠到源代码中是值得的。否则就少用一个子查询。
相关:
- 选择其他表中不存在的行
同时写入
在Postgres 9.5或更高版本中使用Postgres
1 2 3 4 5 6 7 8 9 | INSERT INTO tbl (col1,col2) SELECT DISTINCT * -- still can't insert the same row more than once FROM ( VALUES (text 'v1', text 'v2') , ('v3','v4') , ('v3','v4') -- you still need to fold dupes in source! ) t(c1, c2) ON CONFLICT DO NOTHING; -- ignores rows with *any* conflict! |
更详细的相关答案:
- 如何在PostgreSQL中使用返回with on conflict?
- 如何插入包含外键的行?
文档:
- 手册
- 提交页面
- Postgres wiki页面
克雷格对
- 如何向上插入(合并、插入…在PostgreSQL中?
它会停止整个查询并引发异常吗?对。
为了避免这种情况,您可以在这里查看下面的so问题,它描述了如何避免Postgres在DB上已经存在一些插入的键时对多个插入抛出错误。
你基本上应该这样做:
1 2 3 4 5 6 7 | INSERT INTO DBtable (id, field1) SELECT 1, 'value' WHERE NOT EXISTS ( SELECT id FROM DBtable WHERE id = 1 ); |