【问题标题】:postgresql 9.5.7: INSERT WHERE NOT IN (or NOT EXISTS) not working with bulk-insert of multiple lines at oncepostgresql 9.5.7:INSERT WHERE NOT IN(或 NOT EXISTS)不能同时批量插入多行
【发布时间】:2018-01-08 19:02:51
【问题描述】:

我想将行从一个表 t2 复制到另一个 t1,同时排除 t1 中已存在值的行。 'NOT IN' 的常用方法可以正常工作,但前提是源表 t2 中没有多次出现相同值。

现在,假设我有两个带有架构的表:

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 的数据拆分为“干净”t1 和“脏”t1_faulty,其中收集了所有行不符合某些给定的标准(其中一个是我要问这个问题的 id 的唯一性)。

【问题讨论】:

  • 您能否在两个示例的 instert 之后显示您希望获得的结果?现在,您已经向我们展示了两个不起作用的查询。我真的不明白第一个示例 - t1 有 1,您将插入 12 到 t1排除 t1 中已存在值的行。对我来说,这个查询非常有效 - 它只插入 2 并跳过 1
  • select 在插入数据之前收集数据。
  • @Abelisto:是的,这似乎是问题所在。我可以像 essaferaaimeu 建议的那样解决它。
  • @krokodilko:所需的结果将在 t1 : '1, 2' 但不是两次 2 : '1, 2, 2' 就像我的代码块的最后一个示例一样。但感谢 essaferaaimeu 的建议,我可以解决它。

标签: postgresql where-clause not-exists notin


【解决方案1】:

我认为您可以简单地从源表 (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

【讨论】:

  • 感谢您的回复,essaferaaimeu。它确实像oyu建议的那样工作。感谢那。 :) 干杯!
猜你喜欢
  • 2011-11-05
  • 2018-01-08
  • 1970-01-01
  • 2016-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-21
  • 2015-07-06
相关资源
最近更新 更多