插入多行时重复项会发生什么?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了插入多行时重复项会发生什么?相关的知识,希望对你有一定的参考价值。

我正在运行一个python脚本,将大量数据插入到Postgres数据库中,我使用单个查询来执行多行插入:

INSERT INTO table (col1,col2) VALUES ('v1','v2'),('v3','v4') ... etc

我想知道如果它碰到插入的重复键会发生什么。它会停止整个查询并抛出异常吗?或者它只是忽略该特定行的插入并继续前进?

答案

INSERT将只插入所有行,没有什么特别的事情会发生,除非你有某种constraint不允许重复/重叠值(PRIMARY KEYUNIQUECHECKEXCLUDE约束) - 你在你的问题中没有提到。但这就是你可能担心的事情。

假设UNIQUE上的(col1,col2)或PK约束,你正在处理教科书UPSERT情况。许多相关的问题和答案可以在这里找到。

通常,如果违反了任何约束,则会引发异常(除非陷入像plpgsql这样的过程服务器端语言),不仅会回滚语句,还会回滚整个事务。

Without concurrent writes

即:没有其他事务会尝试同时写入同一个表。

同时处理这两种技术的一种技术是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;

没有关键词EXCEPTALL折叠源中的重复行。如果你知道没有欺骗,EXCEPT ALL或其他技术之一会更快。有关:

通常,如果目标表很大,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 1
   FROM   tbl
   WHERE  col1 = t.c1 AND col2 = t.c2
   );

如果可以有很多欺骗,那么首先在源中折叠它们是值得的。否则使用一个子查询。

有关:

With concurrent writes

在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!

更详细的相关答案:

文档:

克雷格对UPSERT问题的参考答案:

另一答案

它会停止整个查询并抛出异常吗?是。

为避免这种情况,您可以查看以下SO问题here,该问题描述了当DB上已存在某些插入的键时,如何避免Postgres为多次插入引发错误。

你基本上应该这样做:

INSERT INTO DBtable
        (id, field1)
    SELECT 1, 'value'
    WHERE
        NOT EXISTS (
            SELECT id FROM DBtable WHERE id = 1
);

以上是关于插入多行时重复项会发生什么?的主要内容,如果未能解决你的问题,请参考以下文章

从数组中删除重复项会在最终结果中留下重复值

在 ms-access 表中插入多行的 SQL 代码

使用select将多行插入表中,但是表在oracle SQL中具有主键[重复]

MYSQL意外插入多行

带有 MySQL 的 NodeJS - 从数组中向 SQL 插入多行的最佳方法 [重复]

插入多行查询失败[重复]