多行插入或选择(如果存在)

时间:2014-02-27 22:32:48

标签: sql postgresql common-table-expression sql-insert

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最后。

1 个答案:

答案 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