Ограничения внешнего ключа в Oracle - PullRequest
4 голосов
/ 05 мая 2011

У меня есть модель отношений сущностей (ERD), в которой сущности IndividualCategory и TeamCategory относятся к сущности Category.Теперь я хочу создать таблицы в БД Oracle.Я начал так:

CREATE TABLE Category(
    category_id INT PRIMARY KEY,
    ...
);

CREATE TABLE Individual_category(
    category_id INT CONSTRAINT fk_cat_indivcat REFERENCES Category(category_id),
    ...,
    CONSTRAINT pk_indivgamecat PRIMARY KEY (category_id)
);

CREATE TABLE Team_category(
    category_id INT CONSTRAINT fk_cat_teamcat REFERENCES Category(category_id),
    ...,
    CONSTRAINT pk_teamcat PRIMARY KEY (category_id)
);

Эта комбинация Внешний ключ и Первичный ключ гарантирует, что для каждой Individual_category будет соответствующая запись в Category «супер» таблица (или «родительская» таблица?).И будет только одна запись IndividualCategory для конкретной записи Category.То же самое для Team_category.

Для обеспечения наследования мне нужно еще одно ограничение: ограничение, гарантирующее, что для каждой записи в Category будет либо запись в IndividualCategory (X) ИЛИ запись в TeamCategory, но не оба.

Как создать такое ограничение?


РЕДАКТИРОВАТЬ: Это то, что я имел в виду под «наследованием в модели ER».Это из слайдов моего учителя БД (там они называют это «подтипом сущности», но иногда они называют это просто наследованием): enter image description here

Ответы [ 4 ]

4 голосов
/ 05 мая 2011

Совершенно другой способ сделать это, используя отложенные ограничения:

CREATE TABLE Category(
    category_id INT PRIMARY KEY,
    team_category_id INT,
    individual_category_id INT,
    ...
);

CREATE TABLE Individual_category(
    individual_category_id INT PRIMARY KEY,
    category_id INT NOT NULL,
    ...,
);

CREATE TABLE Team_category(
    team_category_id INT PRIMARY KEY,
    category_id INT NOT NULL,
    ...,
);

Убедитесь, что Category - это TeamCategory или IndividualCategory:

alter table Category add constraint category_type_check check
  (   (team_category_id is null and individual_category_id is not null)
   or (team_category_id is not null and individual_category_id is null)
  );

Создание отложенных ограничений целостности, чтобы можно было вставить Category и Team / Individual_Category в одну и ту же транзакцию; в противном случае вы не можете вставить категорию перед TeamCategory / IndividualCategory и наоборот. Улов-22.

alter table category add constraint category_team_fk 
  foreign key (team_category_id)
    references team_category (team_category_id) 
    deferrable initially deferred;

alter table category add constraint category_individual_fk 
  foreign key (individual_category_id)
    references individual_category (individual_category_id) 
    deferrable initially deferred;

alter table individual_category add constraint individual_category_fk
  foreign_key (category_id) 
  references category (category_id)
  deferrable initially deferred;

alter table team_category add constraint team_category_fk
  foreign_key (category_id) 
  references category (category_id)
  deferrable initially deferred;
2 голосов
/ 05 мая 2011

Как это можно сделать, используя упрощенный пример:

CREATE TABLE Category(
    category_id INT PRIMARY KEY,
    category_type varchar2(300) not null,
    ...
    [list of required attributes for only individual category, but nullable],
    [list of required attributes for only team category, but nullable]
);

alter table category add constraint check_category_individual check
  (   category_type <> 'INDIVIDUAL' 
   or (    category_type = 'INDIVIDUAL' 
       and [list of individual category attributes IS NOT NULL]
      )
  );

alter table category add constraint check_category_team check
  (   category_type <> 'TEAM' 
   or (    category_type = 'TEAM' 
       and [list of team category attributes IS NOT NULL]
      )
  );

Затем вы можете создавать представления, например:

create view individual_category as
select category_id, [base category attributes], [individual category attributes]
  from category
 where category_type = 'INDIVIDUAL;

Вы даже можете поместить триггер INSTEAD OF в представление, чтобы приложение выглядело как таблица, как и любой другой.

0 голосов
/ 05 мая 2011

ERD наследование является классическим примером шаблона проектирования Gen-Spec.Существует множество статей о том, как проектировать gen-spec в реляционной СУБД, такой как Oracle.некоторые из них можно найти, выполнив поиск в Google по «реляционному моделированию специализации обобщения».

Многое из того, что вы увидите в этих статьях, уже было изложено в других ответах на этот вопрос.Эта тема много раз появлялась в SO.Для примера предварительного обсуждения нажмите здесь .

. Главная особенность классического решения состоит в том, что специализированные таблицы имеют столбец id, который является как первичным ключом, так и внешним ключом, который ссылается наСтолбец id обобщенной таблицы.Таким образом, субъекты не приобретают собственную идентичность.Особенностью, которую вы действительно должны остерегаться, является ограничение, реализующее дизъюнкцию.Не все статьи применяют это правило в представленном решении.

0 голосов
/ 05 мая 2011

Еще один способ реализации сложных ограничений в базе данных - использование материализованных представлений (MV).

Для этого примера MV можно определить следующим образом:

create materialized view bad_category_mv
refresh complete on commit 
as
select c.category_id
from category c
left outer join individual_category i on i.category_id = c.category_id
left outer join team_category i on t.category_id = c.category_id
where (  (i.category_id is null and t.category_id is null)
      or (i.category_id is not null and t.category_id is not null)
      );

alter table bad_category_mv
add constraint bad_category_mv_chk
check (1=0) deferrable;

Таким образом, MV заполняется только для категорий, которые нарушают правило, но тогда проверочное ограничение гарантирует, что любая транзакция, которая приводит к строке в MV, не будет выполнена (поскольку 1 = 0 никогда не выполняется).

В прошлом я писал об этом подходе здесь .

ВНИМАНИЕ: Хотя я заинтересован в этом подходе, я никогда не использовал его "в гневе" в производственной базе данных. Требуется тщательный бенчмаркинг, чтобы гарантировать, что издержки полного обновления MV при каждом изменении данных не слишком высоки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...