Мне не понятно, зачем вам нужно указывать FRUIT_TYPE в таблице TASKS. На первый взгляд, это просто плохая (ненормализованная) модель данных.
По моему опыту, лучший способ моделирования данных такого типа - использовать супертип для универсального элемента (FRUIT в вашем примере) и подтипы для специфики (APPLE, GRAPE, BANANA). Это позволяет нам хранить общие атрибуты в одном месте при записи конкретных атрибутов для каждого экземпляра.
Вот таблица супертипов:
create table fruits
(fruit_id number not null
, fruit_type varchar2(10) not null
, constraint fruit_pk primary key (fruit_id)
, constraint fruit_uk unique (fruit_id, fruit_type)
, constraint fruit_ck check (fruit_type in ('GRAPE', 'APPLE', 'BANANA'))
)
/
FRUITS имеет первичный ключ и составной уникальный ключ. Нам нужен первичный ключ для использования в ограничениях внешнего ключа, потому что составные ключи - это боль в шее. За исключением случаев, когда это не так, что является ситуацией с этими таблицами подтипов. Здесь мы используем уникальный ключ в качестве ссылки, потому что, ограничивая значение FRUIT_TYPE в подтипе, мы можем гарантировать, что записи в таблице GRAPES отображаются в записи FRUITS типа 'GRAPE' и т. Д.
create table grapes
(fruit_id number not null
, fruit_type varchar2(10) not null default 'GRAPE'
, seedless_yn not null char(1) default 'Y'
, colour varchar2(5) not null
, constraint grape_pk primary key (fruit_id)
, constraint grape_ck check (fruit_type = 'GRAPE')
, constraint grape_fruit_fk foreign key (fruit_id, fruit_type)
references fruit (fruit_id, fruit_type)
, constraint grape_flg_ck check (seedless_yn in ('Y', 'N'))
)
/
create table apples
(fruit_id number not null
, fruit_type varchar2(10) not null
, apple_type varchar2(10) not null default 'APPLE'
, constraint apple_pk primary key (fruit_id)
, constraint apple_ck check (fruit_type = 'APPLE')
, constraint apple_fruit_fk foreign key (fruit_id, fruit_type)
references fruit (fruit_id, fruit_type)
, constraint apple_type_ck check (apple_type in ('EATING', 'COOKING', 'CIDER'))
)
/
create table bananas
(fruit_id number not null
, fruit_type varchar2(10) not null default 'BANANA'
, constraint banana_pk primary key (fruit_id)
, constraint banana_ck check (fruit_type = 'BANANA')
, constraint banana_fruit_fk foreign key (fruit_id, fruit_type)
references fruit (fruit_id, fruit_type)
)
/
В 11g мы можем сделать FRUIT_TYPE виртуальным столбцом для подтипа и устранить ограничение проверки.
Итак, теперь нам нужна таблица для типов задач («Пил», «Охлаждение», «Ешь» и т. Д.).
create table task_types
(task_code varchar2(4) not null
, task_descr varchar2(40) not null
, constraint task_type_pk primary key (task_code)
)
/
А настоящая таблица TASKS - это простое пересечение между FRUITS и TASK_TYPES.
create table tasks
(task_code varchar2(4) not null
, fruit_id number not null
, constraint task_pk primary key (task_code, fruit_id)
, constraint task_task_fk ask foreign key (task_code)
references task_types (task_code)
, constraint task_fruit_fk foreign key (fruit_id)
references fruit (fruit_id)
/
Если это не удовлетворяет вашим потребностям, отредактируйте ваш вопрос, включив в него дополнительную информацию.
"... если вы хотите разные задачи для разных фруктов ..."
Да, я задавался вопросом, была ли это мотивация, лежащая в основе размещенного дизайна ОП. Но обычно рабочий процесс намного сложнее, чем этот: некоторые задачи будут применяться ко всем фруктам, некоторые - только, скажем, к фруктам, которые идут в пучках, другие - только к бананам.
"В нашей реальной логике" фрукты "- это совершенно разные таблицы с
очень мало общего. Думайте клиенты, сотрудники, встречи, комнаты,
здания, теги активов и т. д. Список шагов должен быть
в свободной форме и позволяют пользователям указывать действия с любой из этих вещей. "
Итак, у вас есть куча существующих таблиц. Вы хотите иметь возможность назначать записи из этих таблиц задачам в свободном стиле, но при этом иметь возможность идентифицировать конкретную запись, которой принадлежит задача.
Я думаю, вам все еще нужна общая таблица для хранения идентификатора актера в задании, но вам нужно как-то связать его с другими таблицами. Вот как я мог бы подойти к этому:
Пример существующих таблиц:
create table customers
(cust_id number not null
, cname varchar2(100) not null
, constraint cust_pk primary key (fruit_id)
)
/
create table employees
(emp_no number not null
, ename varchar2(30) not null
, constraint emp_pk primary key (fruit_id)
)
/
Общая таблица для размещения актеров:
create table actors
(actor_id number not null
, constraint actor_pk primary key (actor_id)
)
/
Теперь вам нужны таблицы пересечений, чтобы связать существующие таблицы с новой:
create table cust_actors
(cust_id number not null
, actor_id number not null
, constraint cust_actor_pk primary key (cust_id, actor_id)
, constraint cust_actor_cust_fk foreign key (cust_id)
references customers (cust_id)
, constraint cust_actor_actor_fk foreign key (actor_id)
references actors (actor_id)
)
/
create table emp_actors
(emp_no number not null
, actor_id number not null
, constraint emp_actor_pk primary key (emp_no, actor_id)
, constraint emp_actor_emp_fk foreign key (emp_no)
references eployees (emp_no)
, constraint cust_actor_actor_fk foreign key (actor_id)
references actors (actor_id)
)
/
Таблица ЗАДАЧ довольно неудивительна, учитывая то, что было раньше:
create table tasks
(task_code varchar2(4) not null
, actor_id number not null
, constraint task_pk primary key (task_code, actor_id)
, constraint task_task_fk ask foreign key (task_code)
references task_types (task_code)
, constraint task_actor_fk foreign key (actor_id)
references actors (actor_id)
/
Я согласен, что все эти таблицы пересечений выглядят как большие накладные расходы, но нет другого способа применить ограничения внешнего ключа. Дополнительным препятствием является создание записей ACTORS и CUSTOMER_ACTORS каждый раз, когда вы создаете запись в CUSTOMERS. То же самое для удалений. Единственная хорошая новость заключается в том, что вы можете сгенерировать весь необходимый код.
Является ли это решение лучше таблицы с сотней необязательных внешних ключей? Возможно, нет: это вопрос вкуса. Но мне это нравится больше, чем отсутствие внешних ключей. Если в практике работы с базами данных существует универсальная истина, то это так: базы данных, использующие код приложения для обеспечения реляционной целостности, - это базы данных, в которых дети ссылаются на неправильного родителя или вообще не ссылаются на родителя.