Внешние ключи + наследование таблиц в PostgreSQL?
У меня есть три таблицы: organization
, organization_teams
и org_users
. Здесь organization_teams
наследуется от organization
. Предположим, что если запись добавлена в organizations_teams
, она получит таблицу organization
id
как значение для столбца id
в organization_teams
.
org_users
имеет внешний ключ в столбце id
organization
. Теперь, когда я пытаюсь вставить данные в org_users
, он дает мне ошибку, как показано ниже
insert or update on table "org_users" violates foreign key constraint "org_users_organizations"
DETAIL: Key (org_id)=(12) is not present in table "organizations"
Почему?
Ответы
Ответ 1
Это в руководстве пользователя.
Короткий вариант: вы можете использовать внешние ключи или наследование таблицы, но не оба. Это по своей сути невозможно, просто так сложно технически реализовать уникальные индексы, которые быстро и надежно охватывают унаследованные таблицы в PostgreSQL. Без этого у вас не может быть полезного внешнего ключа. Никто не успешно реализовал его достаточно хорошо, чтобы патч добавил поддержку, которая будет принята в PostgreSQL.
Внешний ключ может указывать на таблицу, которая является частью иерархии наследования, но она точно найдет строки в этой таблице. Не в каких-либо родительских или дочерних таблицах. Чтобы увидеть, какие строки видит внешний ключ, выполните SELECT * FROM ONLY thetable
. Ключевое слово ONLY
означает "игнорирование наследования" и то, что будет искать внешний ключ.
Ответ 2
Единственное обходное решение, которое я нашел:
- создать функцию, возвращающую триггер для проверки существования некоторого id
в унаследованной таблице
- создать триггер ограничения вместо FK
Ответ 3
Полностью согласен с @Craig Ringer, мы не можем использовать внешние ключи вместе с наследованием.
Но если мы уверены, что собираемся вставить правильные данные и хотим использовать внешний ключ в org_users, мы можем сделать одну вещь.
Мы можем создать дочернюю таблицу org_users, скажем org_users_child (без внешнего ключа), как показано ниже
CREATE TABLE org_users_child () INHERITS (org_users);
Теперь мы можем вставить данные в эту дочернюю таблицу.
Теперь, если мы запросим таблицу org_users, мы сможем найти желаемые результаты.