在一个命令中选择或插入一行

时间:2011-07-17 06:39:18

标签: postgresql

我正在使用PostgreSQL 9.0,我有一个只有一个人工密钥(自动递增序列)和另一个唯一密钥的表。 (是的,这个表有一个原因。:))我想通过另一个键查找一个ID,如果它不存在,请插入它:

SELECT id
FROM mytable
WHERE other_key = 'SOMETHING'

然后,如果不匹配:

INSERT INTO mytable (other_key)
VALUES ('SOMETHING')
RETURNING id

问题:是否可以通过在一个语句中执行这两个操作来保存到DB的往返?如果它不存在,我可以插入行:

INSERT INTO mytable (other_key)
SELECT 'SOMETHING'
WHERE NOT EXISTS (SELECT * FROM mytable WHERE other_key = 'SOMETHING')
RETURNING id

...但是这不会给出现有行的ID。有任何想法吗?如果有帮助的话,对other_key有一个唯一的约束。

4 个答案:

答案 0 :(得分:34)

你尝试过联合吗?


编辑 - 这需要Postgres 9.1:

create table mytable (id serial primary key, other_key varchar not null unique);

WITH new_row AS (
INSERT INTO mytable (other_key)
SELECT 'SOMETHING'
WHERE NOT EXISTS (SELECT * FROM mytable WHERE other_key = 'SOMETHING')
RETURNING *
)
SELECT * FROM new_row
UNION
SELECT * FROM mytable WHERE other_key = 'SOMETHING';

结果:

 id | other_key 
----+-----------
  1 | SOMETHING
(1 row)

答案 1 :(得分:3)

使用9.5,我成功地尝试了此

  • 基于Denis de Bernardy的回答
  • 仅1个参数
  • 没有工会
  • 没有存储过程
  • 原子的,因此没有并发问题(我认为...)

查询:

WITH neworexisting AS (
    INSERT INTO mytable(other_key) VALUES('hello 2') 
    ON CONFLICT(other_key) DO UPDATE SET existed=true -- need some update to return sth
    RETURNING * 
)
SELECT * FROM neworexisting

首次通话:

id|other_key|created            |existed|
--|---------|-------------------|-------|
 6|hello 1  |2019-09-11 11:39:29|false  |

第二次通话:

id|other_key|created            |existed|
--|---------|-------------------|-------|
 6|hello 1  |2019-09-11 11:39:29|true   |

首先创建您的表格;-)

CREATE TABLE mytable (
    id serial NOT NULL,
    other_key text NOT NULL,
    created timestamptz NOT NULL DEFAULT now(),
    existed bool NOT NULL DEFAULT false,
    CONSTRAINT mytable_pk PRIMARY KEY (id),
    CONSTRAINT mytable_uniq UNIQUE (other_key) --needed for on conflict
);

答案 2 :(得分:2)

不,没有特殊的SQL语法允许您进行选择或插入。你可以做Ilia所提到的并创建一个sproc,这意味着它不会从客户端到服务器进行往返,但它仍然会导致两个查询(实际上是三个查询,如果你计算sproc本身)。

答案 3 :(得分:1)

您可以使用存储过程

IF (SELECT id FROM mytable WHERE other_key = 'SOMETHING' LIMIT 1) < 0 THEN
 INSERT INTO mytable (other_key) VALUES ('SOMETHING')
END IF