PostgreSQL LinuxWindowsсервер PostgreSQL

PostgreSQL: В PostgreSQL не работает INSERT из-за нарушения внешнего ключа

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

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

INSERT в PostgreSQL прекращается с SQLSTATE 23503 (foreign_key_violation): дочерняя строка ссылается на несуществующий родительский ключ, либо нарушен порядок загрузки. Проверка защищает целостность данных.

В этой статье
  1. Симптом и границы применимости
  2. Как отличить возможные причины
  3. Пошаговая диагностика и безопасное исправление
  4. Как проверить, что проблема устранена
  5. Если исправление не помогло

#Симптом и границы применимости

INSERT в PostgreSQL прекращается с SQLSTATE 23503 (foreign_key_violation): дочерняя строка ссылается на несуществующий родительский ключ, либо нарушен порядок загрузки. Проверка защищает целостность данных.

#Как отличить возможные причины

Возможная причинаКак узнатьЧто делать
Нет родителяСтолбец ссылается на ID, отсутствующий в родительской таблице.DETAIL Key (...) is not presentСоздать реальную родительскую строку
Перепутан порядок импортаДочерние строки загружаются до родительских.Ошибка при восстановлении или миграцииУпорядочить импорт
Неправильный ключ в приложенииПередан ID другого пользователя или арендатора.Ошибка для конкретных запросовИсправить источник ID

#Пошаговая диагностика и безопасное исправление

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

#Как проверить, что проблема устранена

Корректный INSERT успешно фиксируется, при неверном parent_id защита 23503 продолжает срабатывать, связанных сиротских строк нет.

#Если исправление не помогло

Если родитель существует, проверьте подключение к правильной базе, схеме, RLS и используемые параметры; начните с идентификаторов из реального лога.

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

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

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