SQLite LinuxWindows

SQLite: UNIQUE constraint failed при вставке записи

  • Обновлено
  • Чтение ≈ 4 минуты

Краткий ответ

Запись нарушает ограничение уникальности: такое значение уже есть в столбце. Ниже — причины и порядок действий от простого к сложному.

В этой статье
  1. Что означает ошибка
  2. Причины и решения
  3. Пошаговое решение
  4. Диагностика
  5. Обработка конфликтов
  6. Исправление данных

#Что означает ошибка

Сообщение
sqlite3.IntegrityError: UNIQUE constraint failed: users.email

Ошибка «UNIQUE constraint failed: table.column» возникает при попытке вставить или изменить строку так, что значение в уникальном столбце (или составном ключе) дублируется. Это защита от дублей, а не сбой базы.

Нужно решить, что делать с дублем: пропустить, обновить или исправить логику приложения.

SQLite поддерживает явную обработку конфликтов.

Повторное уникальное значение — не ошибка повреждения. Сначала определите, почему возник дубль; INSERT OR IGNORE может скрыть другие нарушения ограничений, а INSERT OR REPLACE может удалить существующую запись и породить каскадные изменения. Предпочитайте управляемую обработку конфликта и диагностику причины.

#Причины и решения

Возможная причинаКак узнатьЧто делать
Дубликат значенияПовторяется уникальный email/ключНайдите запись и определите бизнес-правило обработки дубля.
Повторная вставкаЗапись повторно отправлена с формы/сетиИсправьте защиту от повторных запросов и обработку конфликта.
Неверный ключON CONFLICT отсутствует или настроен на другой индексИспользуйте корректную цель конфликта и подходящую версию SQLite.
Регистр значенийПри создании уникального индекса уже есть дублиСначала диагностируйте дубли на копии, удалять только осмысленно.

#Пошаговое решение

  1. Прочитайте таблицу и столбец в ошибкеВ тексте ошибки найдите названия таблицы и столбцов после UNIQUE constraint failed: users.email или имя уникального индекса. Откройте SQL-редактор SQLite (например, консоль sqlite3 для копии базы), затем выполните SELECT sql FROM sqlite_schema WHERE type IN ('table','index') AND tbl_name='users';, заменив users реальным именем. Это покажет, как устроены уникальные ограничения. Сообщение означает конфликт ключа, но не обязательно «испорченную» базу.
    Linux · Терминал (Bash)Команда
    Схема таблицы и поиск существующей записи.
    sqlite3 db.sqlite ".schema users"
    sqlite3 db.sqlite "SELECT * FROM users WHERE email='a@example.com';"
  2. Найдите конфликтующую записьЕсли конфликт возникает на email, сначала в копии базы выполните запрос только на чтение SELECT id, email FROM users WHERE email = 'user@example.com';, заменив значения реальными; для составного UNIQUE укажите все входящие столбцы. Не публикуйте личные данные в журналах. Если строка существует, определите, почему код пытается вставить её повторно: повторная отправка формы, импорт, конкурирующие запросы или ошибочный идентификатор. Если запись не находится, проверьте транзакции и правильность используемой базы.
  3. Решите стратегиюРешение зависит от смысла данных. Если повторный запрос можно пропустить, приложение должно сообщать «уже существует» или корректно обрабатывать конфликт. Если запись нужно обновить, заранее определите, какие поля разрешено менять; не заменяйте все значения без проверки. Если ввод пользователя неверен, предложите исправить значение. Сначала испытайте вариант на тестовом экземпляре и сравните результат, не удаляйте существующую запись как универсальный выход.
  4. Используйте ON CONFLICTДля SQLite версии 3.24.0 и новее при подходящем уникальном ограничении можно использовать INSERT INTO users (email, name) VALUES (?, ?) ON CONFLICT(email) DO NOTHING; либо согласованное DO UPDATE SET name=excluded.name; знак ? означает параметры, которые передаёт код приложения, а не значение для прямого ввода в терминале. Не путайте это со старым INSERT OR REPLACE: REPLACE может удалить существующую строку и создать новую, нарушая связи. Проверьте SELECT sqlite_version(); и тесты на повторы.
  5. Почистите дубли перед созданием индексаЕсли UNIQUE-индекс требуется добавить в существующую таблицу, сначала сделайте .backup, затем выполните диагностический SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*)>1; на копии; замените поля реальными. Решение о слиянии/удалении дублей принимайте по бизнес-правилам: автоматическое удаление может разрушить ссылки на записи. После согласованной очистки создайте индекс через миграцию и проверьте целостность внешних ключей. Если ошибка появилась при вставке, создавать новый индекс обычно не нужно.

#Диагностика

В сообщении указаны таблица и столбец. Найдите конфликтующую строку: SELECT * FROM users WHERE email = 'a@b.ru';. Найдите существующие дубликаты: SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1;. Просмотрите схему: .schema users — какие UNIQUE и PRIMARY KEY есть. Помните, что NULL значения в уникальном индексе не конфликтуют.

#Обработка конфликтов

SQLite позволяет использовать INSERT ... ON CONFLICT(...) DO NOTHING/DO UPDATE для конкретного уникального индекса начиная с 3.24.0; цель конфликта должна соответствовать схеме. INSERT OR REPLACE может фактически удалить старую строку и нарушить ссылки — не используйте его как общий способ исправления.

#Исправление данных

Перед добавлением UNIQUE-индекса найдите дубли через GROUP BY ... HAVING COUNT(*)>1 на копии базы, затем определите по бизнес-правилам, как их объединять. Запросы автоматического удаления по rowid могут уничтожить связанные данные и недопустимы без согласованного плана. Если ошибка возникла при обычной вставке, новый индекс не нужен.

SQLКоманда
Поиск дубликатов и вставка с обновлением при конфликте.
SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1;
INSERT INTO users(email, name) VALUES('a@b.ru', 'Ann') ON CONFLICT(email) DO UPDATE SET name = excluded.name;

Так эту ошибку тоже называют

Источники и обновления

Последнее обновление статьи: 1 ноября 2026. Версии программ и интерфейсы меняются — если шаги не совпадают с вашей версией, сверяйтесь с документацией производителя.