postgresql 9.5.7:INSERT WHERE NOT IN(或 NOT EXISTS)不能同时批量插入多行

postgresql 9.5.7: INSERT WHERE NOT IN (or NOT EXISTS) not working with bulk-insert of multiple lines at once

我想将一个 table t2 中的行复制到另一个 t1,同时排除 t1 中已存在值的行。 'NOT IN' 的常用方法可以正常工作,但前提是源 table t2.

中没有多次出现相同的值

现在,假设我有两个 tables 架构:

CREATE TABLE t1 ( id INTEGER );
CREATE TABLE t2 ( id INTEGER );

然后将数据插入其中:

INSERT INTO t1 VALUES (1);
INSERT INTO t2 VALUES (1);
INSERT INTO t2 VALUES (2);

现在,我尝试将 t2 中的所有数据插入 t1,但排除 t1 中预先存在的数据:

INSERT INTO t1 (id) SELECT t2.id FROM t2 
    WHERE t2.id NOT IN ( SELECT t1.id FROM t1 WHERE t1.id = t2.id );

它运行完美; t2 中值为“1”的行没有第二次插入到 t1 中:

SELECT * FROM t1;

 id 
----
  1
  2
(2 rows)

但是当 t2 中多次出现相同的值时,它不会检查它们是否存在于每个插入的 t1 中,而是检查整个事务.让我们继续我的示例:

DELETE FROM t1;

INSERT INTO t2 VALUES (2);

SELECT * FROM t2;

 id 
----
  1
  2
  2
(3 rows)

INSERT INTO t1 (id) SELECT t2.id FROM t2 
    WHERE t2.id NOT IN ( SELECT t1.id FROM t1 WHERE t1.id = t2.id );

SELECT * FROM t1;

 id 
----
  1
  2
  2
(3 rows)

使用 WHERE NOT EXISTS 也可以获得相同的结果。

有没有人知道如何在单个行级别检查 t1 中的现有值以防止多次出现?

我也可以使用 ON CONFLICT DO ...但我不想这样做,因为我的想法是将来自 t2 的数据拆分为 "clean" t1 和 "dirty" t1_faulty 收集所有不符合某些给定标准的行(其中之一是我问这个问题的 id 的唯一性)。

我认为您可以简单地从源中过滤您想要的记录 table (t2)。

你可能会用到 distinct on

INSERT INTO t1 (id) SELECT distinct on (t2.id) t2.id FROM t2 
    WHERE t2.id NOT IN ( SELECT t1.id FROM t1 WHERE t1.id = t2.id );

group by

INSERT INTO t1 (id) SELECT t2.id FROM t2 
    WHERE t2.id NOT IN ( SELECT t1.id FROM t1 WHERE t1.id = t2.id ) group by t2.id;

或者,如果您只想要 t2 上已经唯一的记录,请添加 having count = 1

INSERT INTO t1 (id) SELECT t2.id FROM t2 
    WHERE t2.id NOT IN ( SELECT t1.id FROM t1 WHERE t1.id = t2.id )
    group by t2.id
having count(t2.id) = 1