我正在运行一个Python脚本,将大量数据插入到Postgres数据库中,我使用单个查询来执行多行插入:
INSERT INTO table (col1,col2) VALUES ('v1','v2'),('v3','v4') ... etc
我想知道如果插入时遇到重复的键会发生什么。它会停止整个查询并抛出异常吗?还是只会忽略那一行的插入并继续执行下去?
我正在运行一个Python脚本,将大量数据插入到Postgres数据库中,我使用单个查询来执行多行插入:
INSERT INTO table (col1,col2) VALUES ('v1','v2'),('v3','v4') ... etc
我想知道如果插入时遇到重复的键会发生什么。它会停止整个查询并抛出异常吗?还是只会忽略那一行的插入并继续执行下去?
使用WHERE NOT EXISTS ...
或任何其他适用的技术来排除已经存在于表中的行:
别忘了在插入的集合内部也要删除重复项,这些重复项不会被半反连接WHERE NOT EXISTS ...
所排除。
处理两者的一种技术是使用EXCEPT
:
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;
EXCEPT
(除了)关键字不带ALL
会在源中折叠重复行。如果您知道没有重复,或者不想默默地折叠重复项,请使用EXCEPT ALL
(或其他技术之一)。请参见:
通常,如果目标表很大,则在源上使用DISTINCT
与WHERE NOT EXISTS
相结合可能会更快:
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 FROM tbl
WHERE col1 = t.c1 AND col2 = t.c2
);
在Postgres 9.5或更高版本中使用Postgres的UPSERT
实现{{link2:INSERT ... ON CONFLICT ...
}}:
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!
UPSERT
问题的参考答案:
它会停止整个查询并抛出异常吗?是的。
为了避免这种情况,您可以查看以下SO问题here,其中描述了如何在某些已存在于DB中的插入键时避免Postgres抛出多个插入错误。
您应该基本上这样做:
INSERT INTO DBtable
(id, field1)
SELECT 1, 'value'
WHERE
NOT EXISTS (
SELECT id FROM DBtable WHERE id = 1
);