2016-02-20 65 views
2

我有一個簡單的表:我該怎麼辦某種UPSERT內的Postgres 9.5

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

等。 現在我得到一個新的記錄。如果名稱和時間戳相等,我希望數量增加新記錄的數量,否則應該插入新記錄。

喜歡的東西:

INSERT INTO test.data (NAME, TIMESTAMP, AMOUNT) values ('Name1', 123, 4) 
IF not EXIST; OTHERWISE UPDATE test.data set AMOUNT + NEWAMOUNT where TIMESTAMP = oldTimestamp and NAME = oldName 

這在某種程度上可能與使用的是Postgres 9.5一個簡單的SQL查詢?

感謝

回答

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解決方案),這是不是針對併發更新安全,你可能有競爭條件

+0

其實,留名時間戳是唯一的。這兩者聯合是唯一的..表中還有一個ID是實際的主鍵.. – Christian

+0

@Christian:給定你使用名稱,時間戳的方式,但你確實認爲它是唯一的。 –

+0

也許我誤解了你,但正如你在例子中看到的那樣,NAME和TIMESTAMP可以(也將會)發生很多次。它實際上是一個彙總表,它說:名稱爲bla的傳感器在TIMESTAMP和AMOUNT實例中處於活動狀態 – Christian

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