#Что происходит и когда возникает
«foreign key mismatch» отличается от «FOREIGN KEY constraint failed»: SQLite не может сопоставить объявление внешнего ключа дочерней таблицы с подходящим первичным или уникальным ключом родителя. Сбой может проявиться только при INSERT/UPDATE/DELETE после изменения PRIMARY KEY, удаления UNIQUE либо смены коллации. Удалять строки ребёнка или выключать контроль внешних ключей — неправильное первое действие.
#Возможные причины: как различить
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Ссылка осталась на старый ключМиграция изменила имя/число полей PRIMARY KEY в родительской таблице, а дочерняя схема не обновлена. | PRAGMA foreign_key_list(child) показывает старые поля; sqlite_schema содержит новый родительский ключ. | Согласованно пересоздать внешние ключи в миграции. |
| Родительский ключ больше не уникальныйFOREIGN KEY может ссылаться только на PRIMARY KEY или подходящий UNIQUE с корректной collation. | В schema нет UNIQUE на указанных полях или коллация индекса и колонок различается. | Исправить родительский ключ и связи, не маскируя проблему. |
| Другое число столбцов составного ключаВ объявлении REFERENCES не указаны колонки, а PRIMARY KEY родителя состоит из нескольких. | Количество колонок дочернего FK не соответствует составному PK. | Сопоставить все колонки явно и проверить типы. |
#Пошаговая диагностика и исправление
- Остановите изменение данных по ошибочной связиЕсли ошибка появилась после миграции, отключите именно проблемную операцию приложением, не отключая внешние ключи во всей базе. Запишите таблицу, текст ошибки и недавнее изменение схемы. Чтение данных и резервное копирование обычно остаются возможны.
- Проверьте, к какой базе подключеныВ SQL-консоли нужного приложения выполните PRAGMA database_list;. Сверьте путь основной базы с настройками. Затем запросите SELECT name,sql FROM sqlite_schema WHERE type='table' AND name IN ('parent','child');, подставив имена своих таблиц; это покажет исходные определения.
- Посмотрите фактическое объявление внешнего ключаВыполните PRAGMA foreign_key_list(child);. В ответе сравните столбцы from (дочерняя таблица) и to (родительская). Если to пуст, ссылка идёт на PRIMARY KEY родителя. Проверьте PRAGMA table_info(parent); и PRAGMA index_list(parent);, не делая изменений.
- Проверьте индексы и совпадение полейЕсли связь направлена не на PRIMARY KEY, найдите соответствующий UNIQUE-индекс, состав колонок и collation через PRAGMA index_xinfo(имя_индекса);. Для составного ключа важны все поля и их число. Не добавляйте случайный UNIQUE: на реальных данных он может не создаться из-за повторов.
- Подготовьте копию перед миграциейСоздайте резервную копию SQLite через Online Backup API и проверьте PRAGMA integrity_check;. На копии проверьте PRAGMA foreign_key_check; — он диагностирует значения связей, но при неверной схеме сам может сообщить mismatch. Отдельно зафиксируйте строки, которые требуют сопоставления новых ключей.
- Исправьте связь согласованной миграциейЕсли поменялся PK, спроектируйте пересоздание дочерней таблицы с правильным REFERENCES и копированием строк, соблюдая документированную последовательность SQLite для изменения схемы. Это работа миграции, а не отдельная универсальная команда ALTER COLUMN: SQLite не поддерживает произвольный ALTER CONSTRAINT для такой правки. Убедитесь, что старые идентификаторы сопоставлены новым и нет потерянных строк.
- Проверьте тестовую миграциюНа копии включите PRAGMA foreign_keys=ON; до начала транзакций, затем выполните тестовые INSERT/UPDATE по штатному сценарию. Пустой результат PRAGMA foreign_key_check и отсутствие foreign key mismatch в приложении подтверждают исправление. Если ошибка остаётся, остановите перенос и вернитесь к схеме до миграции.
#Команды и проверочные примеры
PRAGMA foreign_key_list(child);PRAGMA table_info(parent);PRAGMA index_list(parent);PRAGMA foreign_key_check;PRAGMA foreign_keys = ON;
CREATE TABLE p(id INTEGER PRIMARY KEY, code TEXT);
CREATE TABLE c(id INTEGER PRIMARY KEY, parent_id INTEGER REFERENCES p(id));
INSERT INTO p(id, code) VALUES(1, 'A');
INSERT INTO c(id, parent_id) VALUES(1, 1);
PRAGMA foreign_key_check;#Как проверить результат
После миграции PRAGMA foreign_key_list показывает точный родительский столбец; PRAGMA foreign_key_check не возвращает нарушений; разрешённая тестовая вставка проходит, а неправильная ссылка отклоняется как FOREIGN KEY constraint failed (в отличие от mismatch).
#Если не помогло
Если появились несопоставленные записи, прервите миграцию и составьте таблицу соответствия старых и новых ключей; не удаляйте данные для устранения ошибки. Передайте схему обеих таблиц и индексов ответственному разработчику.