Korrektur der Tabellenstruktur zur Vermeidung von "Fehler: Doppelter Schlüsselwert verletzt eindeutige Bedingungen"


14

Ich habe eine Tabelle, die folgendermaßen erstellt wird:

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

Später werden unter Angabe der ID einige Zeilen eingefügt:

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

Zu einem späteren Zeitpunkt werden einige Datensätze ohne id eingefügt und sie nicht mit dem Fehler: Error: duplicate key value violates unique constraint.

Anscheinend wurde die ID als Sequenz definiert:

Bildbeschreibung hier eingeben

Jede fehlgeschlagene Einfügung erhöht den Zeiger in der Sequenz, bis er auf einen Wert erhöht wird, der nicht mehr vorhanden ist und die Abfragen erfolgreich sind.

SELECT nextval('jos_content_id_seq'::regclass)

Was ist falsch an der Tabellendefinition? Was ist der clevere Weg, dies zu beheben?


In PostgreSQL müssen Sie Spalten- und Tabellennamen nicht in Kleinbuchstaben angeben.
Rodrigo,

Antworten:


18

An Ihrer Tabellendefinition ist nichts falsch.
(Außer Hut würde ich verwenden jos_content_idoder etwas anstelle der nicht-deskriptiven Spaltennamen id.
Und ich würde wahrscheinlich verwenden textstattvarchar(50) .

Ihre INSERTAussage ist das Problem.

Wenn Ihre idSpalte als definiert ist serial, sollten Sie keine manuellen Werte für einfügen id. Diese können mit dem nächsten Wert aus der zugehörigen Sequenz kollidieren.

Stellen Sie eine explizite Liste der Zielspalten bereit (was fast immer eine gute Idee für dauerhafte INSERTAnweisungen ist) und lassen Sie serielle Spalten vollständig weg .

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

Wenn Sie die Werte von automatisch generierten Spalten sofort benötigen, verwenden Sie die folgende RETURNINGKlausel :

INSERT ...
RETURNING id;  -- possibly more

Weitere Details in dieser verwandten Antwort zu SO:

Wenn Sie manuelle Einträge in serialSpalten haben, die später zu Konflikten führen können, setzen Sie Ihre Sequenz auf das aktuelle Maximum id, um dies einmal zu beheben :

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

Wo jos_content_id_seqist der Standardname für eine Sequenz, deren Eigentümer jos_content.idSie bereits in der Standardspalte gefunden haben? Scheint xhzt8_content_id_seqin deinem Fall zu sein;


Update: Ein ähnliches Problem tauchte bei SO auf und ich fand eine neue Lösung:


Ist der Text nicht langsamer als varchar (50)?
Rodrigo

2
@ Rodrigo: Nicht in Postgres. Oben finden Sie einen Link zu weiteren Erklärungen: dba.stackexchange.com/a/21496/3684 . Oder hier. dba.stackexchange.com/a/89433/3684
Erwin Brandstetter

Der letzte Test hier < depesz.com/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text > hat mich überzeugt, dass varchar (n) in den meisten Bereichen, in denen eine Größenbeschränkung sinnvoll ist (Personen), schneller ist Namen, E-Mails, Adressen, Artnamen usw.). Text ist schneller (oder gleich), wenn Sie die Länge nicht überprüfen, scheint es.
Rodrigo
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.