Ссылка на одну ИЛИ другую таблицу в Oracle SQL

avatar
mIl3
8 августа 2021 в 20:00
244
1
1

У меня есть одна таблица OBRAZAC

Столбцы:

JIB_OBRASCA
JIB_NARUDZBENICE
TIP_NARUDZBE
IME_ZAPOSLENOG
PREZIME_ZAPOSLENOG
JIB_KLINIKE
NAZIV_ODJELJENJA

В зависимости от значения в столбце TIP_NARUDZBE, которое может быть "M" или "L", JIB_OBRASCA должно ссылаться на таблицу NARUDZBENICA_M или NARUDZBENICA_L

Можно ли это сделать или такой подход совершенно неверен? Я новичок в Oracle SQL, поэтому этот вопрос может быть глупым, но я в отчаянии...

Источник
sticky bit
8 августа 2021 в 20:04
2

У вас не может быть ограничения внешнего ключа, ссылающегося на две разные чередующиеся таблицы, если это то, о чем вы просите. У вас может быть два столбца, по одному для каждой ссылки, и ограничение проверки, которое гарантирует, что только правильный столбец содержит ненулевые данные, или реализовать логику в триггерах самостоятельно.

mathguy
8 августа 2021 в 20:12
3

Какое отношение ваш вопрос имеет к PL/SQL? Кажется, это полностью про Oracle SQL. Если вы считаете, что PL/SQL — это другое название Oracle SQL, вы ошибаетесь. Я отредактирую ваш пост и теги, чтобы удалить все ссылки на PL/SQL.

mathguy
8 августа 2021 в 20:19
1

Вопрос вовсе не глупый. То, что вы хотите сделать, не может быть сделано напрямую, поэтому вам нужен обходной путь. Наиболее элегантным является создание представления на основе union all двух таблиц поиска со столбцом для PK и другим для флага «M» или «L», но для этого вам лучше иметь ограничения в столбце «флаг» в дочерней таблице: столбец должен быть not null и ограничен так, чтобы единственными возможными значениями были «M» и «L». Разумны ли такие ограничения на TIP_NARUDZBE в вашей реальной задаче? Если все в порядке, вы можете использовать представление union all в качестве родительской «таблицы».

Thorsten Kettner
8 августа 2021 в 20:24
0

Можно хранить идентификатор NARUDZBENICA_M в одних строках и идентификатор NARUDZBENICA_L в других строках и иметь оба идентификатора в одном столбце JIB_OBRASCA. Однако тогда у вас не может быть ограничений внешнего ключа для этого столбца, как правильно указал липкий бит. Их предложение иметь два отдельных столбца ID — это хорошо. Вам больше не понадобится TIP_NARUDZBE. Другой вариант — сделать NARUDZBENICA_M и NARUDZBENICA_L одной таблицей. Вы можете использовать проверочные ограничения, чтобы убедиться, что заполнены только его столбцы L или его столбцы M.

mIl3
8 августа 2021 в 20:47
0

@mathguy Я хотел написать Oracle SQL, но каким-то образом написал PL/SQL... Спасибо за редактирование

mIl3
8 августа 2021 в 22:12
0

@mathguy Столбец флага может быть не нулевым и иметь только «M» или «L». Часть, которая меня сейчас смущает, — это использование представления в виде таблицы.

mathguy
8 августа 2021 в 23:30
0

Я подумал о лучшем способе, который я добавлю в ответ. Подход "представление" более сложен - вам нужно создать материализованное представление для union all с быстрым обновлением при фиксации; ограничение PK для материализованного представления и ссылка на MV во внешнем ключе. Самая большая проблема с этим подходом заключается в том, что ограничения целостности для родителя (удаление или обновление значения PK) проверяются только на commit, что не делается в большинстве случаев в Oracle. В любом случае - посмотрите на альтернативу, которую я предлагаю, используя виртуальные столбцы.

Ответы (1)

avatar
mathguy
8 августа 2021 в 23:46
2

Возможно, самым простым обходным решением является добавление виртуальных ("вычисляемых") столбцов и наложение на них ограничений внешнего ключа. Виртуальные столбцы доступны начиная с 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
Thorsten Kettner
9 августа 2021 в 06:48
0

Внешние ключи в виртуальных столбцах для меня совершенно новые. Какое чудесное решение для такого рода отношений. Просто прекрасно. Спасибо за публикацию.

mIl3
9 августа 2021 в 08:35
0

ДА!!!! Оно работает!!! Большое спасибо, это действительно спасло меня.