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
我想将一个 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