如何在Postgres 9.5中做一些upsert

时间:2016-02-20 11:56:13

标签: sql postgresql upsert

我有一张简单的表格:

stack<base*> st;

sub A = sub(10);
sub B = sub(20);

st.push(&A);
st.push(&B);
printf("%d\n", (int)st.size());

sub *C = (sub*)st.top();

等等。 现在我得到了一张新纪录。如果名称和时间戳相等,我希望金额增加新记录的数量,否则应插入新记录。

类似的东西:

NAME    | TIMESTAMP | AMOUNT
--------------------------
Name1   | 123       | 1
Name2   | 123       | 15
Name3   | 124       | 3
Name4   | 125       | 1

使用Postgres 9.5进行一次简单的SQL查询是否可以实现这一点?

由于

2 个答案:

答案 0 :(得分:3)

使用新的on conflict子句:

INSERT INTO test.data (NAME, TIMESTAMP, AMOUNT) 
values ('Name1', 123, 4) 
on conflict (name, timestamp) 
  do update 
    set AMOUNT + excluded.NEWAMOUNT 

这要求您在(name, timestamp)

上定义唯一约束(或索引)

如果您不想让(name, timestamp)独一无二,那么可以使用可写的CTE:

with new_values (name, timestamp, amount) as (
  values ('Name1', 123, 4)
), changed as (
  update data 
     set amount = amount + t.amount
  from new_values nv 
   where data.name = nv.name
     and data.timestamp = nv.timestamp
  returning *
)
insert into data (name, timestamp, amount)
select name, timestamp, amount
from new_values
where not exists (select 1 from changed);

请注意(与on conflict解决方案不同),这对并发更新是不安全的,并且您可能有竞争条件

答案 1 :(得分:3)

with t as (
  update test.data set 
    AMOUNT = AMOUNT + 4 
  where 
    NAME = 'Name1' and TIMESTAMP = 123 
  returning 
    *) -- In the t we have list of updated rows (if any)

insert into test.data(NAME, TIMESTAMP, AMOUMT)
  select 'Name1', 123, 4
  where not exists (select * from t); -- Insert new row in rows was not updated