#Симптом и границы применимости
INSERT в PostgreSQL прекращается с SQLSTATE 23503 (foreign_key_violation): дочерняя строка ссылается на несуществующий родительский ключ, либо нарушен порядок загрузки. Проверка защищает целостность данных.
#Как отличить возможные причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Нет родителяСтолбец ссылается на ID, отсутствующий в родительской таблице. | DETAIL Key (...) is not present | Создать реальную родительскую строку |
| Перепутан порядок импортаДочерние строки загружаются до родительских. | Ошибка при восстановлении или миграции | Упорядочить импорт |
| Неправильный ключ в приложенииПередан ID другого пользователя или арендатора. | Ошибка для конкретных запросов | Исправить источник ID |
#Пошаговая диагностика и безопасное исправление
- 1. Сохраните имя ограничения и данные ошибкиВ журнале приложения найдите 23503, название constraint и DETAIL с ключом; замаскируйте персональные поля. Ошибку 23505 unique_violation разбирают иначе, поэтому не принимайте её за внешний ключ.
- 2. Определите родительскую и дочернюю таблицыВ psql просмотрите ограничения для указанной таблицы через \d, сопоставьте колонку ссылки с целевым столбцом. Не угадывайте по похожим названиям ID.
- Мета-команда psql, чтение; app.order_items — примерТекстКомандаМета-команда psql, чтение; app.order_items — пример.
\d app.order_items
- 3. Проверьте наличие родительской записиПодставьте из DETAIL реальный parent_id в SELECT с ограничением. Запрос должен выполняться с правами, позволяющими видеть строку; RLS может скрывать её от приложения.SQLКомандаpsql, чтение; 42 — пример идентификатора из ошибки.
SELECT id FROM app.orders WHERE id=42 LIMIT 1;
- 4. Проверьте границы транзакцииЕсли родитель создаётся перед дочерним объектом, убедитесь, что обе операции выполняются в нужном порядке и транзакции не откатываются между ними. В отдельном соединении незакоммиченная запись родителя не видна.
- 5. Исправьте источник идентификатораВ тестовой среде передавайте ID действительно созданной родительской строки; не подставляйте первый попавшийся существующий ID ради прохождения проверки. Для импорта обеспечьте загрузку родителей раньше детей.
- 6. Проверяйте отложенные ограничения только при необходимостиЕсли constraint явно DEFERRABLE и бизнес-операция этого требует, допускается согласованный отложенный контроль до COMMIT; обычное ограничение менять на DEFERRABLE без разбора нельзя.
- 7. Прогоните контрольные сценарииНа тестовой базе выполните допустимую вставку с существующим родителем и недопустимую с несуществующим. Первая проходит, вторая по-прежнему завершается 23503; проверку ограничений не отключайте.
#Как проверить, что проблема устранена
Корректный INSERT успешно фиксируется, при неверном parent_id защита 23503 продолжает срабатывать, связанных сиротских строк нет.
#Если исправление не помогло
Если родитель существует, проверьте подключение к правильной базе, схеме, RLS и используемые параметры; начните с идентификаторов из реального лога.