Oracle中的外键约束
我有实体关系模型(ERD),其中实体IndividualCategory
和TeamCategory
与实体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