Naprawianie struktury tabeli, aby uniknąć „Błąd: zduplikowana wartość klucza narusza unikalne ograniczenie”

15

Mam tabelę, która jest tworzona w ten sposób:

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

Później wstawiane są niektóre wiersze określające identyfikator:

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

W późniejszym momencie niektóre rekordy są wstawiane bez identyfikatora i one niepowodzeniem z błędem: Error: duplicate key value violates unique constraint.

Najwyraźniej identyfikator został zdefiniowany jako sekwencja:

wprowadź opis zdjęcia tutaj

Każde nieudane wstawienie zwiększa wskaźnik w sekwencji, aż zwiększy się do wartości, która już nie istnieje, a zapytania zakończą się powodzeniem.

SELECT nextval('jos_content_id_seq'::regclass)

Co jest złego w definicji tabeli? Jaki jest sprytny sposób to naprawić?

Valentin Despa
źródło
W PostgreSQL nie musisz cytować nazw kolumn i tabel, jeśli wszystkie są małe.
Rodrigo,

Odpowiedzi:

19

W definicji tabeli nie ma nic złego.
(Z wyjątkiem kapelusz użyłbym jos_content_idlub coś zamiast non-opisowej nazwy kolumny id.
I prawdopodobnie używać textzamiastvarchar(50) .

Twoje INSERToświadczenie stanowi problem.

Po idzdefiniowaniu kolumny jako serialnie należy wstawiać wartości ręcznych dla id. Mogą one kolidować z następną wartością z powiązanej sekwencji.

Podaj wyraźną listę kolumn docelowych (co prawie zawsze jest dobrym pomysłem dla utrwalonych INSERTinstrukcji) i całkowicie pomiń kolumny szeregowe .

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

Jeśli potrzebujesz natychmiastowych wartości automatycznie generowanych kolumn, skorzystaj z RETURNINGklauzuli :

INSERT ...
RETURNING id;  -- possibly more

Więcej szczegółów w tej pokrewnej odpowiedzi na temat SO:

Jeśli masz ręczne wpisy w serialkolumnach, które mogą później spowodować konflikt, ustaw sekwencję na bieżące maksimum, idaby to naprawić raz :

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

Gdzie jos_content_id_seqjest domyślną nazwą sekwencji należącej do jos_content.id, którą już znalazłeś w kolumnie domyślnej. Wydaje się, że tak jest xhzt8_content_id_seqw twoim przypadku;


Aktualizacja: Podobny problem pojawił się na SO i wymyśliłem nowe rozwiązanie:

Erwin Brandstetter
źródło
Czy tekst nie jest wolniejszy niż varchar (50)?
Rodrigo,
2
@Rodrigo: Not in Postgres. Powyżej znajduje się link do dodatkowych wyjaśnień: dba.stackexchange.com/a/21496/3684 . Lub tu. dba.stackexchange.com/a/89433/3684
Erwin Brandstetter
Ostatni test tutaj < depesz.com/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text > przekonał mnie, że varchar (n) jest szybszy dla większości pól, w których ograniczenie wielkości jest wygodne (ludzie imiona, e-maile, adresy, nazwy gatunków itp.). Wygląda na to, że tekst jest szybszy (lub taki sam), jeśli nie sprawdzisz długości.
Rodrigo,