2016-04-27 14 views
16

私は、2つのカラムにユニークな制約を持つテーブルを使って、confict do update ..構文を使用したいと思います。これは可能ですか?複数のユニークな制約を持つPostgresの競合処理

mytableには、col1とcol2に固有の制約があります。

私は書くことができます

INSERT INTO mytable(col1, col2, col3) values ('A', 'B', 0) ON CONFLICT DO NOTHING; 

しかし、これは動作しません。

INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0) 
ON CONFLICT 
DO UPDATE SET col3 = EXCLUDED.col3 + 1; 

ERROR:CONFLICT ONはUPDATEはしていませんまた、この推論の仕様や制約名

が必要でください仕事:

INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0) 
ON CONFLICT (col1, col2) 
DO UPDATE SET col3 = EXCLUDED.col3 + 1; 

エラー:ON CONFLICT仕様に一致する一意または除外の制約はありません

この構文は、2つの制約ではなく2つの列にわたる単一の複合一意制約に対して設計されているようです。

いずれかの一意制約に違反すると、条件付き更新を実行する方法はありますか?この質問How to upsert in Postgres on conflict on one of 2 columns?はそれを暗に示していますが、構文を提供していません。

+0

IMHO質問は意味しません。 「単純な競合の場合」:キーが保持され、従属フィールドの一部(一部)が更新されます。あなたの場合、別の(候補の)鍵を更新するつもりです。実際、あなたは両方の(候補)キーを更新しようとしますが、それは私のロジックを超えています。 – wildplasser

+0

この例をもっと現実的に更新しました。アイデアは、いずれかのユニークな列に一致するカウンタ列を最新の状態に保つか、どちらも存在しない場合はゼロを挿入することです。 –

+2

特別な制約 'UNIQUE(col1、col2) 'を追加すると、おそらくあなたが望むことができます。 (論理的には冗長ですが、データモデルはとにかくほとんどまたは全く意味がありません) – wildplasser

答えて

14

節には、DO UPDATEと尋ねるときに一意の制約が1つ必要です。主キーが定義されている場合は、列名を参照するだけで十分です。これは主な例である。

あなたが「col1とcol2の上に別のユニークな制約」を持っていることは言うので、私はあなたのテーブル定義は、これに似ていると仮定かもしれません:

CREATE TABLE mytable(  
    col1 varchar UNIQUE,  
    col2 varchar UNIQUE,  
    col3 int 
); 

しかし、あなたのクエリは、複合制約を参照しています。別々の制約ではなく、このような変更された表の定義:

CREATE TABLE mytable2( 
    col1 varchar UNIQUE, 
    col2 varchar UNIQUE, 
    col3 int, 
    CONSTRAINT ux_col1_col2 UNIQUE (col1,col2) 
); 

は、上記のクエリでは動作します:

INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0) 
ON CONFLICT (col1, col2) 
DO UPDATE SET col3 = EXCLUDED.col3 + 1; 

は、次のいずれかON CONFLICT (col1, col2)ON CONFLICT ON CONSTRAINT ux_col1_col2などとして、このユニーク制約を参照することができます。

しかし、待って、より多くのがあります...あなたはここに取っているよりも、別のパスをだ

The idea is to keep a counter column up to date which matches on either unique column, or insert zero if neither exists...

。 「はいずれかのユニークな列に一致します」は、両方で一致するか、どちらにも一致しません。私があなたの意図を理解している場合は、単一のラベルをつけて、該当するレコードのカウンターを増やしてください。したがって:

CREATE TABLE mytable2( 
    col1 varchar PRIMARY KEY, 
    col3 int 
); 
INSERT INTO mytable2(col1,col3) 
SELECT incr_label,0 
FROM (VALUES ('A'),('B'),('C')) as increment_list(incr_label) 
ON CONFLICT (col1) 
DO UPDATE SET col3 = mytable2.col3 + 1 
RETURNING col1,col3; 
関連する問題