我有一张桌子需要插件。如果该行已存在,那么我想更新并返回该行。如果该行还没有存在,那么我需要插入并返回该行。通过下面的查询,我得到插入时返回的行,但不会更新。
Table "main.message_account_seen"
Column | Type | Modifiers
----------------+--------------------------+-------------------------------------------------------------------
id | integer | not null default nextval('message_account_seen_id_seq'::regclass)
field_config_id | integer | not null
edit_stamp | timestamp with time zone | not null default now()
audit_stamp | timestamp with time zone |
message_id | integer | not null
account_id | integer |
这是sql。
with upsert as (
update message_account_seen set (message_id, account_id, field_config_id ) = (1, 60, 980)
where message_id = 1 and account_id = 60 and field_config_id = 980 returning *
)
insert into message_account_seen (message_id, account_id, field_config_id)
select 1, 60, 980
where not exists (select message_id, account_id, field_config_id from upsert) returning *;
我不能做postgres函数,需要在常规的sql查询中处理。此外,表的唯一性没有约束,否则我会使用on conflict
。但我愿意废弃此查询,并在需要时使用其他内容。
这些是我运行查询然后再次运行它时的结果。你可以看到在插入或第一次运行时我得到了返回的行。但是在后续运行的查询中,我得到0行返回。我知道它正在工作,因为edit_stamp会随着时间的推移而增加。这是一件好事。
# with upsert as (
update message_account_seen set (message_id, account_id, field_config_id ) = (1, 60, 980)
where message_id = 1 and account_id = 60 and field_config_id = 980 returning *
)
insert into message_account_seen (message_id, account_id, field_config_id)
select 1, 60, 980
where not exists (select message_id, account_id, field_config_id from upsert) returning *;
id | field_config_id | edit_stamp | audit_stamp | message_id | account_id
--+-----------------+--------------------------------+-------------+------------+------------
38 | 980 | 09/27/2016 11:43:22.153908 MDT | | 1 | 60
(1 row)
INSERT 0 1
# with upsert as (
update message_account_seen set (message_id, account_id, field_config_id ) = (1, 60, 980)
where message_id = 1 and account_id = 60 and field_config_id = 980 returning *
)
insert into message_account_seen (message_id, account_id, field_config_id)
select 1, 60, 980
where not exists (select message_id, account_id, field_config_id from upsert) returning *;
id | field_config_id | edit_stamp | audit_stamp | message_id | account_id
----+-----------------+------------+-------------+------------+------------
(0 rows)
INSERT 0 0
答案 0 :(得分:2)
更新成功后,查询中不会返回结果。这样做:
with upsert as (
update message_account_seen
set (message_id, account_id, field_config_id ) = (1, 60, 980)
where (message_id, account_id, field_config_id) = (1, 60, 980)
returning *
), ins as (
insert into message_account_seen (message_id, account_id, field_config_id)
select 1, 60, 980
where not exists (select 1 from upsert)
returning *
)
select * from upsert
union all
select * from ins
;
答案 1 :(得分:1)
这里最好的选择是使用postgres 9.5提供的新upsert,但这需要(message_id, account_id, field_config_id)
上的唯一索引。它可以像这样使用:
INSERT INTO message_account_seen(message_id, account_id, field_config_id)
VALUES (1, 60, 980)
ON CONFLICT (message_id, account_id, field_config_id)
DO UPDATE
SET edit_stamp=now() -- adjust here
RETURNING *;
这可能是执行此操作的最快方法,并保证如果两个进程同时尝试插入同一个表中,则不会发生任何意外情况(您的方法无法保证)。