2017-06-02 5 views
1

大きなデータベースで一意のインデックス違反が発生しました。元の問題は、格納されたpl/pgsql関数で発生します。更新中のユニークなインデックス違反

問題を示すためにすべてを単純化しました。私はむしろ単純なテーブルでそれを再現することができます:UPDATEは、テーブル内のデータが次のようになります前に

CREATE UNIQUE INDEX test_idx_pos 
    ON public.test 
    USING btree 
    (pos); 

testdb=# SELECT * FROM test; 
id | pos | text 
----+-----+---------- 
    2 | 1 | testpos1 
    3 | 2 | testpos2 
    1 | 5 | testpos4 
    4 | 4 | testpos3 
(4 Zeilen) 
tr: (4 rows) 

CREATE TABLE public.test 
(
    id integer NOT NULL DEFAULT nextval('test_id_seq'::regclass), 
    pos integer, 
    text text, 
    CONSTRAINT text_pkey PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 

ALTER TABLE public.test 
    OWNER TO root; 
GRANT ALL ON TABLE public.test TO root; 

は、私が「POS」に一意索引を定義します

今、私は2より大きいすべての 'pos'の値を1減らしたいと思っています(trはドイツ語から英語への私の翻訳です):

UPDATEが完全に実行していた場合は
testdb=# UPDATE test SET pos = pos - 1 WHERE pos > 2; 
FEHLER: doppelter Schlüsselwert verletzt Unique-Constraint »test_idx_pos« 
tr: ERROR: duplicate key violates unique constraint »test_idx_pos« 
DETAIL: Schlüssel »(pos)=(4)« existiert bereits. 
tr: key »(pos)=(4) already exists. 

テーブルは次のようになりますし、再びユニークである:

testdb=# SELECT * FROM test; 
id | pos | text 
----+-----+---------- 
    2 | 1 | testpos1 
    3 | 2 | testpos2 
    1 | 4 | testpos4 
    4 | 3 | testpos3 
(4 Zeilen) 
tr: (4 rows) 

にはどうすればこのような事態を回避することができますか?私は、格納されたpl/pgsql関数がトランザクションに組み込まれていることを知ったので、この問題は表示されませんか?

答えて

1

ユニークインデックス

(Oracleの実装に違うなどである)ではないのステートメントごとに、行ごとに評価され、この問題を解決するには、延期することができますので、最後に評価され、ユニークな制約を使用することですその取引のユニークインデックスの

ので代わり、制約を定義します。

alter table test add constraint test_idx_pos unique (pos) 
    deferrable initially deferred; 
+0

この正確な答えや解決のためにありがとうございました。私の「評判」が小さすぎるので、私はあなたの答えをアップアップすることができません申し訳ありません。私はあなたの答えを今受け入れることさえできません。それは唯一のものなのだろうか? – WKarl

+0

ああ、今できます。時間制限。どのように奇妙な。 なぜ私の質問は-1になったのですか?私は質問する前に答えを探しました、それは不明ではありません - 他にどのようにa_horse_with_no_nameが1分で答えることができ、それは少なくとも私にとっては非常に便利です。 – WKarl

関連する問題