Возможно, самым простым обходным решением является добавление виртуальных ("вычисляемых") столбцов и наложение на них ограничений внешнего ключа. Виртуальные столбцы доступны начиная с Oracle 11.1, поэтому, если ваша версия Oracle не находится в музее, вы сможете это сделать.
Начните со следующей настройки - две похожие таблицы в качестве "родителей", каждая из которых имеет столбец id
в качестве первичного ключа. (Таблицы могут иметь другие столбцы - это не имеет отношения к этой иллюстрации.) Кроме того, дочерняя таблица со столбцом «флаг» и «идентификатор» и, возможно, другие столбцы, которые я игнорирую. Вы можете ограничить флаг not null
и только двумя значениями "L" и "M", но это даже не требуется. В конце концов ограничение будет заключаться в том, что если флаг равен «L», то идентификатор должен существовать в родительской таблице «L», а если это «M», то идентификатор должен существовать в «M». «родитель; нет условия для идентификатора в дочерней таблице, если флаг не "L" или "M".
Итак - упрощенная версия вашей существующей установки (я заполнил данными родительские таблицы, но не дочернюю таблицу - для собственного тестирования):
create table l_parent (id primary key) as
select 111 from dual union all
select 113 from dual
;
create table m_parent (id primary key) as
select 111 from dual union all
select 303 from dual
;
create table child_table (flag char(1), id number)
;
Вот как вы можете реализовать свое ограничение. Создайте две виртуальные колонки; возможно, также сделать их невидимыми, чтобы select *
их не отображал — эта функция доступна начиная с Oracle 12.1.
alter table child_table
add (l_id invisible as (case when flag = 'L' then id end) references l_parent,
m_id invisible as (case when flag = 'M' then id end) references m_parent)
;
Вот и все. Для проверки заполните дочернюю таблицу недопустимой строкой (чтобы убедиться, что она отклонена), а затем допустимой строкой. Затем попробуйте удалить из родительской таблицы, где у вас уже есть дочерняя строка, чтобы увидеть, что она тоже отклонена. Что-то вроде этого:
insert into child_table (flag, id) values ('L', 303); -- should fail
insert into child_table (flag, id) values ('M', 303); -- should succeed
delete from m_parent where id = 303; -- should fail now
У вас не может быть ограничения внешнего ключа, ссылающегося на две разные чередующиеся таблицы, если это то, о чем вы просите. У вас может быть два столбца, по одному для каждой ссылки, и ограничение проверки, которое гарантирует, что только правильный столбец содержит ненулевые данные, или реализовать логику в триггерах самостоятельно.
Какое отношение ваш вопрос имеет к PL/SQL? Кажется, это полностью про Oracle SQL. Если вы считаете, что PL/SQL — это другое название Oracle SQL, вы ошибаетесь. Я отредактирую ваш пост и теги, чтобы удалить все ссылки на PL/SQL.
Вопрос вовсе не глупый. То, что вы хотите сделать, не может быть сделано напрямую, поэтому вам нужен обходной путь. Наиболее элегантным является создание представления на основе
union all
двух таблиц поиска со столбцом для PK и другим для флага «M» или «L», но для этого вам лучше иметь ограничения в столбце «флаг» в дочерней таблице: столбец должен бытьnot null
и ограничен так, чтобы единственными возможными значениями были «M» и «L». Разумны ли такие ограничения наTIP_NARUDZBE
в вашей реальной задаче? Если все в порядке, вы можете использовать представлениеunion all
в качестве родительской «таблицы».Можно хранить идентификатор NARUDZBENICA_M в одних строках и идентификатор NARUDZBENICA_L в других строках и иметь оба идентификатора в одном столбце JIB_OBRASCA. Однако тогда у вас не может быть ограничений внешнего ключа для этого столбца, как правильно указал липкий бит. Их предложение иметь два отдельных столбца ID — это хорошо. Вам больше не понадобится TIP_NARUDZBE. Другой вариант — сделать NARUDZBENICA_M и NARUDZBENICA_L одной таблицей. Вы можете использовать проверочные ограничения, чтобы убедиться, что заполнены только его столбцы L или его столбцы M.
@mathguy Я хотел написать Oracle SQL, но каким-то образом написал PL/SQL... Спасибо за редактирование
@mathguy Столбец флага может быть не нулевым и иметь только «M» или «L». Часть, которая меня сейчас смущает, — это использование представления в виде таблицы.
Я подумал о лучшем способе, который я добавлю в ответ. Подход "представление" более сложен - вам нужно создать материализованное представление для
union all
с быстрым обновлением при фиксации; ограничение PK для материализованного представления и ссылка на MV во внешнем ключе. Самая большая проблема с этим подходом заключается в том, что ограничения целостности для родителя (удаление или обновление значения PK) проверяются только наcommit
, что не делается в большинстве случаев в Oracle. В любом случае - посмотрите на альтернативу, которую я предлагаю, используя виртуальные столбцы.