Виправлення структури таблиці, щоб уникнути "Помилка: значення дублювання ключа порушує унікальне обмеження"


15

У мене є таблиця, яка створена таким чином:

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

Пізніше вставляються деякі рядки із зазначенням ідентифікатора:

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

На більш пізньому етапі деякі записи вставляються без ідентифікатора , і вони завершаться з помилкою: Error: duplicate key value violates unique constraint.

Мабуть, ідентифікатор визначили як послідовність:

введіть тут опис зображення

Кожна невдала вставка збільшує вказівник у послідовності, поки він не зросте до значення, яке більше не існує, і запити будуть успішними.

SELECT nextval('jos_content_id_seq'::regclass)

Що не так з визначенням таблиці? Який розумний спосіб це виправити?


У PostgreSQL вам не потрібно цитувати назви стовпців та таблиць, якщо всі вони малі.
Родріго

Відповіді:


19

Нічого не так з визначенням таблиці.
(Окрім капелюха, я б використовував jos_content_idабо щось замість не описової назви стовпців id.
І я, мабуть, використовувавtextvarchar(50) би замість цього .

Ваша INSERTзаява - проблема.

Якщо ваш idстовпець визначений як serial, ви не повинні вставляти значення вручну для id. Вони можуть стикатися з наступним значенням з пов'язаної послідовності.

Надайте чіткий список цільових стовпців (що майже завжди є хорошою ідеєю для збережених INSERTвисловлювань) та повністю опустіть послідовні стовпці .

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

Якщо вам потрібні значення (-и) автоматично сформованих стовпців (-ів), автоматично скористайтеся RETURNINGпунктом :

INSERT ...
RETURNING id;  -- possibly more

Більш детально у цій відповіді на ПЗ:

Якщо у вас є ручні записи в serialстовпцях, які можуть пізніше конфліктувати, встановіть свою послідовність на поточний максимум, idщоб виправити це один раз :

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

Де jos_content_id_seqназва за замовчуванням для належної послідовності jos_content.id, яку ви вже знайшли у стовпці за замовчуванням. Здається, xhzt8_content_id_seqу вашому випадку;


Оновлення: подібна проблема виникла на SO, і я придумав нове рішення:


Чи не текст повільніше, ніж варчар (50)?
Родріго

2
@Rodrigo: Не в Postgres. Наведене вище посилання на додаткові пояснення: dba.stackexchange.com/a/21496/3684 . Або тут. dba.stackexchange.com/a/89433/3684
Ервін

Останній тест тут < depesz.com/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text > переконав мене, що varchar (n) швидший для більшості полів, де обмеження розміру зручне (люди назви, електронні листи, адреси, назви видів тощо). Текст швидше (або однаковий), якщо ви не перевірите довжину, здається.
Родріго
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.