2017-04-23 18 views
0

私は2つのフィールド、lane_idと位置に一意のインデックスを持つテーブルを持っています。PostgreSQL:一意のインデックスを持つ一括更新

は今、私はこのクエリを使用して行を更新したい:私は、複数のチケットをお持ちの場合

duplicate key value violates unique constraint "teams_ticket_position_bfcce9fa_uniq" 

UPDATE "teams_ticket" SET "position" = ("teams_ticket"."position" + 1) WHERE ("teams_ticket"."lane_id" = 1 AND "teams_ticket"."position" >= 0) 

で終わるどの。

どうすればこの問題を解決できますか?

+0

スキーマによって異なります。増分している値に固有のキー制約があるように思えますが、これは修正を開始するのに適しています。 – Makoto

+0

@Makotoはい、私は知っています。私はインデックスを持っています(チケットの最初の行を見てください)。問題は、すべてのチケットを1つのポジションだけシフトすると、有効な状況に終わるはずです(すべてのlane_id - ポジションのペアはまだ一意です)。しかし、彼らは1つずつ移動してインデックスが失敗しているように見えます。私はこの問題を解決する正しい方法が何か不思議です。 – marxin

+1

ここには 'deferrable'が必要です。 – wildplasser

答えて

0

あなたはdeferrableの制約が必要です(実際には一時的に延期します)。遅延可能とは、制約がすぐにチェックされない(インデックスタプルが書き換えられるとき)トランザクション(または文)の最後に、すべての行が更新されたときを意味します。

- \ tmp SQL

CREATE TABLE positions 
     (seq SERIAL PRIMARY KEY 
     , position INTEGER NOT NULL UNIQUE DEFERRABLE 
     ); 

INSERT INTO positions(position) 
SELECT generate_series(1,10) gs; 

BEGIN; 
SET CONSTRAINTS ALL DEFERRED; 

update positions 
SET position= position +1 
WHERE seq <= 6 ; 

SELECT * FROM positions ; 

UPDATE positions SET position= position +1 
WHERE seq > 6 
     ; 

SELECT * FROM positions ; 

UPDATE positions SET position= position +1 
     ; 

SELECT * FROM positions ; 

COMMIT; 
+0

Downvoter:説明してください。 (これは正解ですので、IMnsvHOです) – wildplasser

+0

これは正しい解決策です。一般的に、失敗の理由は制約が* deffered *ではないということでした。 変更テーブルを追加...初期設定を間違えていました これまでは私は最後のビットがありませんでした。初期設定では初期設定はできませんでした。 – marxin

-1

あなたは、あなたがそれらを一つずつを更新するために、カーソルを使用することができます

UPDATE teams_ticket t 
    SET position = q.position + 1 
    FROM (
    SELECT lane_id, position 
     FROM teams_ticket 
    WHERE lane_id = 1 
     AND position >= 0 
    ORDER BY lane_id, position DESC 
) q 
    WHERE t.lane_id = q.lane_id 
    AND t.position = q.position 
+0

これは動作する可能性があります。そうでないかもしれない。サブクエリ内の「ORDER BY」は本質的に役に立たない。オプティマイザはそれを無視するかもしれません。 – wildplasser

0

を試すことができます。

DO $$ 
    DECLARE r record; 
BEGIN 
    FOR r IN SELECT lane_id, position FROM teams_ticket WHERE lane_id=1 AND position >= 0 ORDER BY position DESC 
    LOOP 
    UPDATE teams_ticket SET position=position+1 WHERE position=r.position AND lane_id=r.lane_id; 
    END LOOP; 
END$$; 
関連する問題