插入多行时重复项会发生什么情况?
What happens with duplicates when inserting multiple rows?
我是运行一个将大量数据插入Postgres数据库的python脚本,我使用单个查询执行多行插入:
INSERT INTO table (col1,col2) VALUES ('v1','v2'),('v3','v4') ... etc
我想知道如果它为插入插入一个重复的键会发生什么。它会停止整个查询并抛出异常吗?还是它只会忽略该特定行的插入并继续?
它会停止整个查询并抛出异常吗?是的
为避免这种情况,您可以查看以下 SO 问题 here,它描述了当某些插入的键已存在于数据库中时,如何避免 Postgres 为多次插入抛出错误。
你基本上应该这样做:
INSERT INTO DBtable
(id, field1)
SELECT 1, 'value'
WHERE
NOT EXISTS (
SELECT id FROM DBtable WHERE id = 1
);
INSERT
只会插入所有行,不会发生任何特殊情况,除非 你有某种 constraint 不允许重复/重叠值(PRIMARY KEY
、UNIQUE
、CHECK
或 EXCLUDE
约束)——你没有提到在你的问题中。但这可能就是你担心的。
假设 UNIQUE
或 (col1,col2)
上的 PK 约束,您正在处理教科书 UPSERT
情况。许多相关的问题和答案都可以在这里找到。
通常,如果违反了任何约束,则会引发异常(除非被困在子事务中,就像在 plpgsql 这样的过程服务器端语言中是可能的)将不会回滚只有声明,但是整个交易.
没有并发写入
即:没有其他事务会尝试同时写入相同的 table。
使用 WHERE NOT EXISTS ...
或任何其他适用技术排除 table 中已经存在的行:
Select rows which are not present in other table
并且不要忘记删除 within 插入的重复项,这将 not 排除在外由半反加入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
(或其他技术之一)。参见:
一般来说,如果目标 table 是 大 ,WHERE NOT EXISTS
结合源上的 DISTINCT
可能会更快:
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
);
如果可以有很多重复,首先将它们折叠到源代码中是值得的。否则少用一个子查询。
相关:
- Select rows which are not present in other table
并发写入
在 Postgres 9.5 或更高版本中使用 Postgres UPSERT
实现 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!
延伸阅读:
文档:
Craig 对 UPSERT
个问题的参考答案:
- How to UPSERT (MERGE, INSERT ... ON DUPLICATE UPDATE) in PostgreSQL?
我是运行一个将大量数据插入Postgres数据库的python脚本,我使用单个查询执行多行插入:
INSERT INTO table (col1,col2) VALUES ('v1','v2'),('v3','v4') ... etc
我想知道如果它为插入插入一个重复的键会发生什么。它会停止整个查询并抛出异常吗?还是它只会忽略该特定行的插入并继续?
它会停止整个查询并抛出异常吗?是的
为避免这种情况,您可以查看以下 SO 问题 here,它描述了当某些插入的键已存在于数据库中时,如何避免 Postgres 为多次插入抛出错误。
你基本上应该这样做:
INSERT INTO DBtable
(id, field1)
SELECT 1, 'value'
WHERE
NOT EXISTS (
SELECT id FROM DBtable WHERE id = 1
);
INSERT
只会插入所有行,不会发生任何特殊情况,除非 你有某种 constraint 不允许重复/重叠值(PRIMARY KEY
、UNIQUE
、CHECK
或 EXCLUDE
约束)——你没有提到在你的问题中。但这可能就是你担心的。
假设 UNIQUE
或 (col1,col2)
上的 PK 约束,您正在处理教科书 UPSERT
情况。许多相关的问题和答案都可以在这里找到。
通常,如果违反了任何约束,则会引发异常(除非被困在子事务中,就像在 plpgsql 这样的过程服务器端语言中是可能的)将不会回滚只有声明,但是整个交易.
没有并发写入
即:没有其他事务会尝试同时写入相同的 table。
使用
WHERE NOT EXISTS ...
或任何其他适用技术排除 table 中已经存在的行:Select rows which are not present in other table
并且不要忘记删除 within 插入的重复项,这将 not 排除在外由半反加入
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
(或其他技术之一)。参见:
一般来说,如果目标 table 是 大 ,WHERE NOT EXISTS
结合源上的 DISTINCT
可能会更快:
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
);
如果可以有很多重复,首先将它们折叠到源代码中是值得的。否则少用一个子查询。
相关:
- Select rows which are not present in other table
并发写入
在 Postgres 9.5 或更高版本中使用 Postgres UPSERT
实现 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!
延伸阅读:
文档:
Craig 对 UPSERT
个问题的参考答案:
- How to UPSERT (MERGE, INSERT ... ON DUPLICATE UPDATE) in PostgreSQL?