2012-12-20 42 views
0

我有一個分區表和一個更新函數/觸發器。當一行被更新時,它首先刪除該行,然後將其插入到適當的分區中。我的問題是,我正在嘗試做一個類似於Oracle中的MERGE的聲明。我發現參考Postgres的一個類似的實現使用UPSERT如下列:在分區表上的Postgres中的UPSERT語句

WITH upsert as 
(
    update mytable2 m 
     set sales=m.sales+d.sales, 
      status=d.status 
    from mytable d 
    where m.pid=d.pid 
    RETURNING m.* 
) 
insert into mytable2 
select a.pid, a.sales, 'NEW' 
from mytable a 
where a.pid not in (select b.pid from upsert b); 

然而,問題是更新首先開火 - 導致刪除和特定行插入,然後插入爲再次插入。這是因爲我在分區上的更新函數/觸發器。有沒有什麼辦法像Oracle那樣通過合併(即,如果找到了行,更新它,或者插入它)而使其在Oracle中工作,而不會導致欺騙或在違反約束時失敗?

非常感謝您的幫助!

+0

您有一個更新函數/觸發器,與您發佈的upsert代碼無關嗎? –

+0

因此,以上面的例子來說,更新觸發器將位於mytable2分區表上。觸發器在每個分區上並在更新之前觸發。它刪除OLD.pid = pid所在的行(如上例所示)。然後使用NEW。*值插入。這個函數/觸發器對於管理表是必需的,因爲它是一個大表。我想要做的另一個過程是每天合併到表中,因爲它是一個分析數據庫,我希望獲得新的每日行。如果您還有其他問題,請告訴我。我感謝你的迴應。 – user3412041

+0

對不起,我沒有看到觸發器。我沒有看到分區表。不過,我會用合適的EXISTS結構替換IN。 – wildplasser

回答

0

這裏的問題是在返回null的觸發器的交集處,以及期望返回結果的upserts。從本質上說什麼你做的是:

  1. 刪除行
  2. 插入行
  3. 中止更新(這是您的UPSERT什麼食堂)
  4. 檢查,如果在更新完成,如果沒有插入。

這是一個你會遇到一些問題的情況,因爲你的觸發器會破壞軟件的流程。

因此,如何使這項工作.....

我沒有看到一個簡單的方法,使這項工作在顯著大集。我認爲你將不得不將更新部分移到可以調用的函數中。該函數的細節將取決於您實際上一次更新了多少行。然後你可以做一個INSERT ... SELECT類似於你正在做的事情,但用函數調用而不是CTE。