web-dev-qa-db-fra.com

Correction de la structure de la table pour éviter `Erreur: la valeur de la clé en double viole la contrainte unique`

J'ai une table qui est créée de cette façon:

--
-- 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")
);

Plus tard, certaines lignes sont insérées en spécifiant l'id:

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

Plus tard, certains enregistrements sont insérés sans identifiant et échouent avec l'erreur: Error: duplicate key value violates unique constraint.

Apparemment, l'identifiant a été défini comme une séquence:

enter image description here

Chaque insertion ayant échoué augmente le pointeur dans la séquence jusqu'à ce qu'il augmente jusqu'à une valeur qui n'existe plus et que les requêtes aboutissent.

SELECT nextval('jos_content_id_seq'::regclass)

Quel est le problème avec la définition de la table? Quelle est la façon intelligente de résoudre ce problème?

15
Valentin Despa

Rien ne va mal avec la définition de votre table.
(Sauf si j'utilisais jos_content_id Ou quelque chose à la place du nom de colonne non descriptif id.
Et je le ferais probablement tilisez text au lieu de varchar(50) .

Votre instruction INSERT est le problème.

Avec votre colonne id définie comme serial , vous ne devez pas insérer de valeurs manuelles pour id. Ceux-ci peuvent entrer en collision avec la valeur suivante de la séquence associée.

Fournissez une liste explicite des colonnes cibles (ce qui est presque toujours une bonne idée pour les instructions INSERT persistantes) et omettez complètement les colonnes série .

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

Si vous avez immédiatement besoin de la ou des valeurs des colonnes générées automatiquement, utilisez la clause RETURNING =:

INSERT ...
RETURNING id;  -- possibly more

Plus de détails dans cette réponse connexe sur SO:

Si vous avez des entrées manuelles dans les colonnes serial qui pourraient entrer en conflit ultérieurement, définissez votre séquence sur le maximum actuel id pour corriger ceci une fois:

SELECT setval('jos_content_id_seq', max(id))
FROM   jos_content;

jos_content_id_seq Est le nom par défaut d'une séquence appartenant à jos_content.id, Que vous avez déjà trouvé dans la colonne par défaut. Semble être xhzt8_content_id_seq Dans votre cas;


Mise à jour: Un problème similaire est apparu sur SO et j'ai trouvé une nouvelle solution:

21
Erwin Brandstetter