#Что означает ошибка
duplicate key value
ERROR: duplicate key value violates unique constraint "table_pkey" с подробностью Key (id)=(5) already exists означает вставку значения, которое уже есть в уникальном или первичном ключе. Часто виновата рассогласованная последовательность (sequence) после импорта данных с явными id.
Определите, настоящий ли это дубль или сбой последовательности.
Лечится по-разному.
Вставка нарушает уникальный индекс. Проверьте существующие значения, используйте ON CONFLICT или исправьте последовательность (sequence).
#Причины и решения
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Дубликат значенияДанные. | DETAIL показывает уже существующее значение столбца email или составного ключа | Найдите источник повторной записи, определите, нужно ли пропустить или обновить. |
| Сбитая sequenceСчётчик. | Повторяется конфликт автоматически назначенного id после импорта | Сравните MAX(id) и связанный sequence; изменять sequence только в окно обслуживания. |
| Гонка запросовПараллель. | Два запроса пытаются вставить одинаковый логический ключ одновременно | Используйте UNIQUE и обработку конфликта на уровне транзакции. |
| Импорт данныхРучные id. | После импорта с явными id счётчик мог не обновиться | Проверьте привязанный sequence и согласуйте коррекцию после резервной копии. |
#Пошаговое решение
- Прочитайте Key и constraint в сообщенииОткройте консоль psql (например, на Linux через
sudo -u postgres psql -d ИМЯ_БАЗЫ, если это соответствует вашей системе). Полностью скопируйте текстduplicate key value violates unique constraint "...", особенно строкуDETAIL: Key (email)=(...) already exists. Название ограничения может относиться к первичному ключу, отдельному UNIQUE-индексу или составному ключу. До любых изменений узнайте, какая команда INSERT/UPDATE вызвала ошибку и какая таблица участвовала. Дубликат данных — обычный сценарий, не свидетельство повреждения последовательности. - Найдите конфликтующую строкуЕсли в DETAIL указан реальный столбец, проверьте дубликат запросом только на чтение в SQL-редакторе вашей базы, например
SELECT id, email FROM public.users WHERE email = 'example@example.com';; замените таблицу, столбец и значение на свои и избегайте раскрытия личных данных. Для составного ограничения включите все указанные поля; запрос может не обнаружить строку, если она вставлена другой транзакцией и ещё не видна. Найдите в коде, почему вставка выполняется повторно: повторный запрос, конкурентная запись, неверный ключ или повторный импорт. - Сравните MAX(id) и sequenceЛишь если ошибка относится к автоматически назначаемому числовому
id(SERIAL/IDENTITY), сравните максимальный идентификатор с последовательностью. В psql выполнитеSELECT pg_get_serial_sequence('public.users','id');иSELECT max(id) FROM public.users;, предварительно заменив имена. Если первый запрос возвращает NULL, столбец не имеет связанной последовательности и этот способ не подходит. Не вызывайтеnextvalради диагностики: он изменяет состояние последовательности. Столбецlast_valueвиден только при разрешённом доступе к найденной последовательности. - Выровняйте последовательностьМенять последовательность может только администратор при подтверждённом рассогласовании после импорта, на согласованном окне обслуживания и с резервной копией. При параллельных вставках
setvalможет состязаться с приложением и создать новые дубликаты: сначала обеспечьте отсутствие конкурирующих записей. Для таблицы с непустыми положительными идентификаторами пример —SELECT setval(pg_get_serial_sequence('public.users','id'), (SELECT max(id) FROM public.users), true);; при пустой таблице и иных шагах/минимумах алгоритм будет другим. Проверьте фактическое следующее значение на тестовой вставке, не изменяя производственные записи без согласования. - Используйте ON CONFLICT для настоящих дублейЕсли конфликт возник при повторном создании одной и той же записи, определите бизнес-правило.
INSERT ... ON CONFLICT (email) DO NOTHINGуместен, только когда повтор можно пропустить, аDO UPDATE SET ...— когда действительно нужно обновить существующую запись. Вставьте конструкцию в код приложения и проверьте её в транзакции на тестовой базе: убедитесь, что другое уникальное ограничение не нарушается. Не используйтеON CONFLICTдля маскировки ошибочно повторяющегося запроса или перезаписи важных полей.
#Диагностика
Прочитайте строку DETAIL из исключения и определите, какие значения вызвали конфликт. Для email это обычно реальный дубликат, а для автоматически выдаваемого числового id может быть ошибочный счётчик последовательности. SELECT MAX(id) и pg_get_serial_sequence(...) применяйте только к точной таблице и при подтверждённом сценарии.
#Починка последовательности
Рассогласование sequence исправляет администратор только после резервной копии, проверки реального диапазона идентификаторов и исключения параллельных вставок. setval меняет состояние последовательности и может породить новый конфликт, если выполнить его вслепую. Пустые таблицы, пользовательские начальные значения и шаги последовательности требуют отдельного алгоритма.
#Настоящие дубли
Для ожидаемых повторов можно выбрать ON CONFLICT ... DO NOTHING или контролируемое DO UPDATE, но только в соответствии с правилами приложения и на тестовой базе. Перед созданием UNIQUE-индекса проверьте дубли; автоматическое удаление строк без анализа ссылок и внешних ключей недопустимо.
SELECT pg_get_serial_sequence('public.users','id');SELECT MAX(id) FROM public.users;