Correzione della struttura della tabella per evitare "Errore: il valore chiave duplicato viola un vincolo univoco"


15

Ho una tabella creata in questo modo:

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

Successivamente vengono inserite alcune righe specificando l'id:

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

In un momento successivo alcuni record vengono inseriti senza id e falliscono con l'errore: Error: duplicate key value violates unique constraint.

Apparentemente l'id è stato definito come una sequenza:

inserisci qui la descrizione dell'immagine

Ogni inserimento non riuscito aumenta il puntatore nella sequenza fino a quando non aumenta a un valore che non esiste più e le query hanno esito positivo.

SELECT nextval('jos_content_id_seq'::regclass)

Cosa c'è di sbagliato nella definizione della tabella? Qual è il modo intelligente per risolvere questo problema?


In PostgreSQL, non è necessario citare i nomi di colonne e tabelle se sono tutti in minuscolo.
Rodrigo,

Risposte:


19

Nulla è sbagliato nella definizione della tabella.
(Tranne cappello vorrei usare jos_content_ido qualcosa invece del nome della colonna non descrittivo id.
E probabilmente avrei usare textal posto divarchar(50) .

La tua INSERTaffermazione è il problema.

Con la idcolonna definita come serial, non è necessario inserire valori manuali per id. Quelli possono scontrarsi con il valore successivo della sequenza associata.

Fornire un elenco esplicito di colonne di destinazione (che è quasi sempre una buona idea per le INSERTdichiarazioni persistenti ) e omettere completamente le colonne seriali .

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

Se hai bisogno immediatamente dei valori delle colonne generate automaticamente, usa la RETURNINGclausola :

INSERT ...
RETURNING id;  -- possibly more

Maggiori dettagli in questa risposta correlata su SO:

Se hai voci manuali in serialcolonne che potrebbero entrare in conflitto in un secondo momento, imposta la sequenza sul massimo corrente idper risolvere il problema una volta :

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

Dove si jos_content_id_seqtrova il nome predefinito per una sequenza di proprietà di jos_content.id, che hai già trovato nella colonna predefinita. Sembra essere xhzt8_content_id_seqnel tuo caso;


Aggiornamento: un problema simile è emerso su SO e ho trovato una nuova soluzione:


Il testo non è più lento di varchar (50)?
Rodrigo,

2
@Rodrigo: non in Postgres. C'è un link sopra per ulteriori spiegazioni: dba.stackexchange.com/a/21496/3684 . O qui. dba.stackexchange.com/a/89433/3684
Erwin Brandstetter

L'ultimo test qui < depesz.com/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text > mi ha convinto che varchar (n) è più veloce per la maggior parte dei campi in cui è conveniente una limitazione di dimensioni (persone nomi, e-mail, indirizzi, nomi di specie, ecc.). Sembra che il testo sia più veloce (o uguale) se non si controlla la lunghezza.
Rodrigo,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.