web-dev-qa-db-ja.com

「エラー:キー値の重複が一意制約に違反しています」を回避するためにテーブル構造を修正する

この方法で作成されたテーブルがあります。

_--
-- Table: #__content
--
CREATE TABLE "jos_content" (
  "id" serial NOT NULL,
  "asset_id" bigint DEFAULT 0 NOT NULL,
   ...
  "xreference" varchar(50) DEFAULT '' NOT NULL,
  PRIMARY KEY ("id")
);
_

その後、IDを指定していくつかの行が挿入されます。

INSERT INTO "jos_content" VALUES (1,36,'About',...)

後で、一部のレコードがIDなしで挿入され、次のエラーで失敗します:_Error: duplicate key value violates unique constraint_。

どうやらidはシーケンスとして定義されました:

enter image description here

挿入が失敗するたびに、ポインターは、存在しない値にインクリメントされてクエリが成功するまで、シーケンスのポインターを増やします。

SELECT nextval('jos_content_id_seq'::regclass)

テーブル定義の何が問題になっていますか?これを修正するスマートな方法は何ですか?

15
Valentin Despa

テーブルの定義に問題はありません。
(ただし、説明のない列名idの代わりに_jos_content_id_などを使用します)。
そして、おそらく varchar(50) の代わりにtextを使用します。

あなたのINSERTステートメントが問題です。

id列が serial として定義されている場合、idに手動で値を挿入しないでください。それらは、関連するシーケンスの次の値と衝突する可能性があります。

ターゲット列の明示的なリスト(永続化されたINSERTステートメントの場合は、ほとんどの場合に適切です)およびシリアル列を削除を完全に提供します。

_INSERT INTO jos_content(asset_id, some_column, ...)
VALUES (36,'About',...);
_

自動生成された列の値がすぐに必要な場合は、 RETURNING を使用します。

_INSERT ...
RETURNING id;  -- possibly more
_

SOに関するこの関連回答の詳細:

後で競合する可能性があるserial列に手動のエントリがある場合は、シーケンスを現在の最大値idfix thisに設定します1回

_SELECT setval('jos_content_id_seq', max(id))
FROM   jos_content;
_

ここで、_jos_content_id_seq_は、_jos_content.id_が所有するシーケンスのデフォルト名であり、列のデフォルトですでに見つかりました。あなたの場合は_xhzt8_content_id_seq_のようです。


Update:同様の問題がSOでポップアップし、新しい解決策が思い付きました:

21