Oracle中的外键约束

我有实体关系模型(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_category ,在Category “超级”表(或“父”表)中将会有相应的记录。 对于特定的Category记录将只有一个IndividualCategory记录。 Team_category相同。

为了执行继承,我需要一个约束:一个约束,确保对于Category中的每个记录,都会有IndividualCategory (X)中的记录或TeamCategory的记录,但不是两者都有。

我如何创建这样的约束?


编辑:这就是我所说的'ER模型中的继承'。 这是来自我的数据库老师的幻灯片(他们称之为“实体子类型”,但有时称它为继承): 在这里输入图像描述


一种完全不同的方式使用可延迟的约束来做到这一点:

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个人Category

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)
  );

创建可延迟的完整性约束,以便可以在同一事务中插入类别和团队/个人_类别; 否则,您无法在TeamCategory / IndividualCategory之前插入类别,反之亦然。 一个catch-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;

人们如何做到这一点,使用一个简化的例子:

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


另一种在数据库中实现复杂约束的方法是使用物化视图(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刷新的开销不会太高。

链接地址: http://www.djcxy.com/p/65255.html

上一篇: Foreign Key Constraints in Oracle

下一篇: What's the difference between identifying and non