CREATE TABLE object (
object_id serial,
object_attribute_1 integer,
object_attribute_2 VARCHAR(255)
)
-- primary key object_id
-- btree index on object_attribute_1, object_attribute_2
以下是我目前的情况:
SELECT * FROM object
WHERE (object_attribute_1=100 AND object_attribute_2='Some String') OR
(object_attribute_1=200 AND object_attribute_2='Some other String') OR
(..another row..) OR
(..another row..)
当查询返回时,我检查缺少的内容(因此,数据库中不存在)。
然后我将进行多行插入:
INSERT INTO object (object_attribute_1, object_attribute_2)
VALUES (info, info), (info, info),(info, info)
然后我将选择刚刚插入的内容
SELECT ... WHERE (condition) OR (condition) OR ...
最后,我将合并客户端的两个选择。
有没有办法可以将这3个查询组合到一个查询中,我将提供所有数据,INSERT
如果记录尚不存在,然后执行SELECT
最后。
答案 0 :(得分:1)
你的怀疑是有根据的。使用data-modifying CTE(Postgres 9.1 +)在单个语句中完成所有操作:
WITH list(object_attribute_1, object_attribute_2) AS (
VALUES
(100, 'Some String')
, (200, 'Some other String')
, .....
)
, ins AS (
INSERT INTO object (object_attribute_1, object_attribute_2)
SELECT l.*
FROM list l
LEFT JOIN object o1 USING (object_attribute_1, object_attribute_2)
WHERE o1.object_attribute_1 IS NULL
RETURNING *
)
SELECT * FROM ins -- newly inserted rows
UNION ALL -- append pre-existing rows
SELECT o.*
FROM list l
JOIN object o USING (object_attribute_1, object_attribute_2);
请注意,竞争条件的时间范围很短。因此,如果许多客户同时尝试它,这可能会破裂。如果您在大量并发负载下工作,请考虑此相关答案,尤其是锁定或serializable transaction isolation上的部分:
Postgresql batch insert or ignore