Oracle中的外键约束

时间:2011-05-05 00:17:46

标签: sql oracle database-design data-modeling foreign-key-relationship

我有实体关系模型(ERD),其中实体IndividualCategoryTeamCategory与实体Category相关。现在我想在Oracle DB中创建表。我开始是这样的:

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_categoryCategory“超级”表中都有相应的记录(或“父”表?)。对于特定的IndividualCategory记录,只有一个Category记录。与Team_category相同。

为了强制继承,我还需要一个约束:一个约束,确保Category中的每个记录都有IndividualCategory(X)中的记录或TeamCategory中的记录。不是两个。

如何创建此类约束?


编辑:这就是我所说的'E-R模型中的继承'。这是我的数据库老师的幻灯片(他们称之为“实体子类型”,但他们有时称之为继承):enter image description here

4 个答案:

答案 0 :(得分:4)

使用可延迟约束完全不同的方法:

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 xor和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;

答案 1 :(得分:2)

如何使用简化示例:

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触发器,以便应用程序看起来像任何其他表格一样。

答案 2 :(得分:0)

在数据库中实现复杂约束的另一种方法是使用物化视图(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永远不会为真)。

我过去曾在here发表过关于此方法的博客。

注意:虽然我对这种方法感兴趣,但我从未在生产数据库中“愤怒地”使用它。需要仔细的基准测试,以确保每当数据发生变化时,完整MV刷新的开销不会太高。

答案 3 :(得分:0)

ERD继承是gen-spec设计模式的典型例子。关于如何在像Oracle这样的关系型DBMS中设计gen-spec有很多文章。您可以通过Google搜索“泛化专业化关系建模”找到其中一些。

您将在这些文章中看到的大部分内容已经通过对此问题的其他回复进行了概述。这个话题在SO中多次浮出水面。有关事先讨论的示例,click here

经典解决方案的主要特性是专用表具有一个id列,它既是主键,又是引用通用表的id列的外键。以这种方式,子实体不会获得他们自己的身份。您真正需要注意的功能是实现析取的约束。并非所有文章都在其提出的解决方案中强制执行此规则。