sql - Postgres : upsert a row and update a primary key column

标签 sql postgresql merge upsert

假设我的 Postgres 数据库中有两个表:

create table transactions
(
    id bigint primary key,
    doc_id bigint not null,
    -- lots of other columns...
    amount numeric not null
);

-- same columns
create temporary table updated_transactions
(
    id bigint primary key,
    doc_id bigint not null,
    -- lots of other columns...
    amount numeric not null
);

两个表都只有一个主键,没有唯一索引。

我需要使用以下规则将 updated_transactions 中的行更新到 transactions 中:

  • transactionsupdated_transactions 中的 id 列值不匹配
  • doc_id 等其他列(金额 除外)应匹配
  • 找到匹配行后,更新 amountid
  • 当没有找到匹配的行时,插入它
updated_transactions 中的

id 值取自一个序列。 业务对象只是填充 updated_transactions 然后合并 使用 upsert 查询将新的或更新的行从它转换为 transactions。 所以我的旧的未更改交易保持它们的 id 不变,而更新的交易 被分配了新的 id

在 MSSQL 和 Oracle 中,这将是一个类似这样的 merge 语句:

merge into transactions t
using updated_transactions ut on t.doc_id = ut.doc_id, ...
when matched then
    update set t.id = ut.id, t.amount = ut.amount
when not matched then
    insert (t.id, t.doc_id, ..., t.amount)
    values (ut.id, ut.doc_id, ..., ut.amount);

在 PostgreSQL 中,我想它应该是这样的:

insert into transactions(id, doc_id, ..., amount)
select coalesce(t.id, ut.id), ut.doc_id, ... ut.amount
from updated_transactions ut
left join transactions t on t.doc_id = ut.doc_id, ....
    on conflict
    on constraint transactions_pkey
    do update
    set amount = excluded.amount, id = excluded.id

问题出在 do update 子句上:excluded.id 是旧值 来自 transactions 表,而我需要来自 updated_transactions 的新值。

ut.id 值对于 do update 子句是不可访问的,我唯一能做的 使用的是 excluded 行。但是 excluded 行只有 coalesce(t.id, ut.id) 返回现有行的旧 id 值的表达式。

是否可以使用 upsert 查询同时更新 idamount 列?

最佳答案

在用作键的那些列上创建唯一索引,并在 upsert 表达式中传递它的名称,以便它使用它而不是 pkey。 然后,如果未找到匹配项,它将使用 updated_transactions 中的 ID 插入行。如果找到匹配项,则您可以使用 excluded.id 从 updated_transactions 获取 ID。

我认为 left join transactions 是多余的。

所以它看起来有点像这样:

insert into transactions(id, doc_id, ..., amount)
select ut.id, ut.doc_id, ... ut.amount
from updated_transactions ut
    on conflict
    on constraint transactions_multi_column_unique_index
    do update
    set amount = excluded.amount, id = excluded.id

关于sql - Postgres : upsert a row and update a primary key column,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43103994/

相关文章:

php - 连接查询的计数

c# - 如何编写一列返回多个结果的SQL查询C#

postgresql - 在文本中查找日期和时间值,然后更新另一列

android - 将多个图像合并为一个图像

git - 如何 git merge --squash 以便 github "network"图显示 merge

mysql - mysql中如何将列转换为数组?

sql - 更改 SQL Server 中的列大小

python - Django/PostgreSQL varchar 到 UUID

PostgreSQL - OSM 数据表连接非常慢

tensorflow - 为对抗性学习的张量板增加值(value)