2017-05-16 115 views
-1

我有一個函數:Postgres的功能,插入和更新

create function fn_name_here() returns int as 
$$ 
begin 
    with c as (
    Select a1.accounts_id,sum(a2.quantity * a2.unit_price) as MRR 
    from account_subscriptions a1 
    inner join order_item a2 on a1.subscription_id = a2.account_subscriptions_id 
    group by a1.accounts_id 
    ) 
    update summary s set MRR = c.MRR 
    from c 
    where c.accounts_id = s.accounts_id; 
return 0; 
end; 
$$ language plpgsql 

與查詢,我得到accounts_idmrr,並通過對比accounts_id更新在summarymrr

但我也需要一個新行accounts_idmrrsummary表中插入如果accounts_id已經不存在在那裏,但它拋出一個錯誤。

,當我與此查詢編輯它,並調用函數

UPDATE dummy s SET mrr = c.MRR from c WHERE c.accounts_id = s.accounts_id ;  
IF NOT FOUND THEN 
    INSERT INTO dummy (mrr,accounts_id) 
     select c.mrr,c.accounts_id from c; 
END IF; 

它引發錯誤

relation "c" does not exist 
LINE 1: ...TO dummy (mrr,accounts_id) select c.mrr,c.accounts_id from c 
+0

爲什麼[tag:mysql]標記? – Jens

+1

請更新帖子,您收到錯誤 –

+0

您正在使用哪個版本的postgres? –

回答

0

c只在UPDATE聲明的範圍存在,並且你不能在同一個函數中從後面的SQL語句中引用它。

不適合使用UPDATE,您應該使用INSERT ... ON CONFLICT ... UPDATE,它完全符合您的需求。您需要的只是summary(accounts_id)上的主鍵或唯一約束。

+0

此功能從postgres 9.5及更高版本可用。 @naina如果你使用9.5或更高版本,那麼這將是最好的解決方案。 –

0

注意:這是在9.4測試。

在9.5或更高版本中插入了新功能。

請按照以下步驟檢查插入或更新。你可以參考這個並相應地更新你的功能。

步驟1:

CREATE TABLE public.test 
(
    col1 text, 
    col2 text, 
    col3 integer 
); 

步驟2:

insert into test values ('Old', 'Old', 1); 

步驟3:

drop function if exists test_insert_update(); 

create function test_insert_update() returns int as 
$$ 
Declare findId boolean; 
begin 
    /* Main Query starts from here as you have asked to create function that is why it is wrapped into it. This is sample example you can 
     modify it as per your requirement. */ 

    with updateInsert as (
    Select '' as col1,'updated' as col2, col3 
    from test abc 
    where col3 = 1 
    union 
    Select 'notUpdated' as col1, 'notUpdated' as col2, 2 as col3 

    ), updateValues as (
     -- this only updates your results 
    update test c1 set col3 = updateInsert.col3 
     , col2 = updateInsert.col2 
    from updateInsert 
    where updateInsert.col3 = c1.col3 
    RETURNING *  
    /* 
     I tried the example using with RETURNING * and without RETURNING * and both the time I recieved expected 
     result but in PostgreSQL documentation it is written in with clause. 
     As per documentation : 9.4 
     INSERT conforms to the SQL standard, except that the RETURNING clause is a PostgreSQL extension, 
     as is the ability to use WITH with INSERT. Also, the case in which a column name list is omitted, 
     but not all the columns are filled from the VALUES clause or query, is disallowed by the standard. 
    */ 
    ) 
    Insert into test (col1, col2, col3) 
    select * from updateInsert where not exists(select * from test c1 where c1.col3 = updateInsert.col3); 
    /* Not exists clause is written to remove rows which has been updated. */ 

    /* END */  
return 0; 
end; 
$$ 
language 'plpgsql'; 

步驟5:

select * from test_insert_update(); 

第6步:

select * from test; 
+0

此代碼受制於競賽條件。如果例如在第一個CTE的'SELECT'之後提交一個併發事務(順便說一句,爲什麼'col3 = 1'和'col3 = 2'是硬編碼的?),而在* INSERT之前,你的功能將失敗。你必須爲'UPSERT'編寫一個無限循環,重試直到'INSERT'或'UPDATE'成功。 –

+0

這些是虛擬查詢只是爲了測試插入和更新。我添加了一個聯合來測試插入功能。據我所知,col3 = 1已經存在於表格中,所以應該更新它,並且應該插入col3 = 3。 –