【发布时间】: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,您将插入1和2到 t1排除 t1 中已存在值的行。对我来说,这个查询非常有效 - 它只插入2并跳过1 -
select在插入数据之前收集数据。 -
@Abelisto:是的,这似乎是问题所在。我可以像 essaferaaimeu 建议的那样解决它。
-
@krokodilko:所需的结果将在 t1 : '1, 2' 但不是两次 2 : '1, 2, 2' 就像我的代码块的最后一个示例一样。但感谢 essaferaaimeu 的建议,我可以解决它。
标签: postgresql where-clause not-exists notin