需要从 upsert 返回的行
Need row returned from upsert
我有一个 table 需要更新。如果该行已经存在,那么我想更新并 return 该行。如果该行尚不存在,那么我需要插入并 return 该行。通过下面的查询,我在插入时得到行 returned,但在更新时没有。
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 查询中处理。此外,对于行的唯一性,table 没有约束,否则我会使用 on conflict
。但如果需要,我愿意放弃这个查询并使用其他东西。
这些是我 运行 查询然后再次 运行 查询时的结果。您可以看到,在插入或第一个 运行 中,我得到了行 returned。但是,在随后的 运行 查询中,我得到 0 行 returned。我知道它正在工作,因为 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
更新成功后,其结果不会返回到您的查询中。这样做:
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
;
此处最好的选择是使用 postgres 9.5 提供的新更新插入,但这需要 (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 *;
这可能是执行此操作的最快方法,并且可以保证如果两个进程同时尝试更新插入到同一个 table 中不会发生任何意外(您的方法不能保证这一点)。
我有一个 table 需要更新。如果该行已经存在,那么我想更新并 return 该行。如果该行尚不存在,那么我需要插入并 return 该行。通过下面的查询,我在插入时得到行 returned,但在更新时没有。
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 查询中处理。此外,对于行的唯一性,table 没有约束,否则我会使用 on conflict
。但如果需要,我愿意放弃这个查询并使用其他东西。
这些是我 运行 查询然后再次 运行 查询时的结果。您可以看到,在插入或第一个 运行 中,我得到了行 returned。但是,在随后的 运行 查询中,我得到 0 行 returned。我知道它正在工作,因为 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
更新成功后,其结果不会返回到您的查询中。这样做:
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
;
此处最好的选择是使用 postgres 9.5 提供的新更新插入,但这需要 (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 *;
这可能是执行此操作的最快方法,并且可以保证如果两个进程同时尝试更新插入到同一个 table 中不会发生任何意外(您的方法不能保证这一点)。