Oracle 中的外键约束

发布于 2024-11-05 00:28:08 字数 1094 浏览 1 评论 0原文

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

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

我如何创建这样的约束?


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

I have Entity Relationship Model (ERD) where entities IndividualCategory and TeamCategory relate to entity Category. Now I want to create tables in Oracle DB. I started like this:

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

This combination of Foreign key and Primary key constraints assures that for every Individual_category there will be corresponding record in Category "super" table (or "parent" table ?). And there will be only one IndividualCategory record for particular Category record. Same for Team_category.

To enforce inheritance I need one more constraint: A constraint that assures that for every record in Category there will be either record in IndividualCategory (X)OR a record in TeamCategory but not both.

How do I create such constraint ?


EDIT: This is what I meant by 'inheritance in E-R model'. This is from my DB teacher's slides (they call it "Entity sub-type" there but they sometimes call it just inheritance):enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

悲欢浪云 2024-11-12 00:28:08

使用可延迟约束来实现此目的的一种完全不同的方法是:

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

确保类别是 TeamCategory x 或 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)
  );

创建可延迟完整性约束,以便可以在同一事务中插入类别和 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;

A completely different way to do this using deferrable constraints:

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

Make sure a Category is a TeamCategory xor an 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)
  );

Create deferrable integrity constraints so that one can insert a Category and Team/Individual_Category within the same transaction; otherwise, you couldn't insert a Category before the TeamCategory/IndividualCategory, and vice-versa. A 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;
浮华 2024-11-12 00:28:08

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

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

How one may do this is, using a simplified example:

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

You could then create views, like:

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

You can even put an INSTEAD OF trigger on the view so it would be appear to the application to be a table like any other.

橘香 2024-11-12 00:28:08

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

Another way to implement complex constraints in the database is using materialized views (MVs).

For this example an MV could be defined as follows:

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;

So the MV is populated only for categories that break the rule, but then the check constraint ensures that any transaction that results in a row in the MV will fail (since 1=0 is never true).

I have blogged about this approach in the past here.

CAUTION: Although I am interested in this approach I have never used it "in anger" in a production database. Careful benchmarking is needed to ensure that the overhead of the full MV refresh whenever the data is changed is not too high.

卸妝后依然美 2024-11-12 00:28:08

ERD 继承是 gen-spec 设计模式的经典示例。有很多关于如何在 Oracle 等关系 DBMS 中设计 gen-spec 的文章。你可以通过谷歌搜索“泛化专业化关系建模”找到其中一些。

您将在这些文章中看到的大部分内容已经在对此问题的其他答复中概述。这个话题在《SO》中已经多次出现。有关先前讨论的示例,单击此处

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

ERD inheritance is a classic example of the gen-spec design pattern. There are numerous articles on how to design gen-spec in a relational DBMS like Oracle. you can find some of them by doing a Google search on "generalization specialization relational modeling".

Much of what you will see in these articles has already been outlined by other responses to this question. This topic has surfaced many times in SO. For a sample prior discussion, click here.

The main feature of the classic solution is that the specialized tables have an id column that is both a primary key and a foreign key that references the id column of the generalized table. In this manner, the subentities do not acquire an identity of their own. The feature you really need to watch out for is the constraint that implements disjunction. Not all of the articles enforce this rule in their presented solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文