相同实体之间的多个连接表

时间:2015-05-09 13:10:21

标签: database database-design relational-database database-schema database-agnostic

我正在规划数据库架构,并且我遇到了一个我不知道最佳方法的情况。我真的在寻找我提出的每个解决方案的优缺点列表,也许后面会推荐符合最佳数据库实践的建议。

所以,问题是我有两个实体,它们之间有多个多对多关系。这两个表是团队和人;团队由许多人组成,一个人可以在团队中拥有一个或多个角色。角色包括团队领导,团队成员,团队追随者等。一个人可能有一个以上的角色为特定团队,但理想情况下这些角色的一部分是互斥的,而其他角色则不是。

以下是我考虑过的解决方案:

1)为每个角色创建一个单独的联结表。每个表中存在一行表示一个人属于一个团队,特定表表示该团队中的人员角色。必须在应用程序级别强制执行互斥角色。

2)创建单个联结表并在该表上存储枚举以指定人员具有的角色。给定的人员 - 团队组合可能在此表中有多行,每个人对该团队的每个角色都有一行。必须在应用程序级别强制执行某些角色的相互排他性。

3)创建一个联结表,并在表上存储一个布尔标志列表,每个角色一个。每个人员 - 团队组合在表中都有一行,并且标志确定用户在该团队中具有哪些角色。可以在数据库级别强制执行相互排他性,因为所有互斥角色可以共享表中的单个枚举字段。

4)创建两个联结表。这是(2)和(1)的组合,允许在数据库级别强制执行互斥。将有一个联结表,其中包含用于互斥角色的枚举,另一个联结表(具有枚举)将处理所有非独占角色。

我有什么遗忘的吗?哪个选项看起来最自然?

由于

2 个答案:

答案 0 :(得分:1)

你偶然发现了派对模特! :)

只需将个人和组织存储在一个表中即可。这称为单表继承。如果使用像PG这样的数据库,那么空值不会占用任何空间。

与角色相同。将它们存放在一个表中,除非它变得笨重。

如果您使用像hibernate这样的ORM来更新数据库模式,那么如果需要,它可以非常轻松地切换到类表继承。我想说STI在开发过程中更容易使用。

答案 1 :(得分:1)

每个人员和团队代表实体。每个交叉点或交叉点表示实体之间的关系。如果您有多个可能的关系,那么有多个联结表是有意义的。

您暗示某些关系可能是互斥的。这是一个很容易修复的问题。

create table CaptainOrMember(
    PersonID  int not null,
    TeamID    int not null,
    C_or_M    char( 1 ) not null,
    constraint PK_CaptainOrMember primary key( PersonID, TeamID ),
    constraint FK_CaptainOrMember_Person foreign key( PersonID )
        references People( ID ),
    constraint FK_CaptainOrMember_Team foreign key( TeamID )
        references Team( ID ),
    constraint CK_CaptainOrMember_OneOrOther check( C_or_M in( 'C', 'M' )
);

这定义了船长和会员关系。只有一个人< - >可以进行团队输入,并且必须使用“C”或“M”进行指定。因此,一个人可以是团队队长或团队成员,但不能两者兼而有之。

它具有使用一个联结表来实现两种关系的附加优势。

也就是说,除非您想要添加到关系元组中,否则只有一个Captain-only和Member-only数据。然后,您可以添加两个“子连接”表。这里他们是为了说明。

alter table CaptainOrMember add constraint UQ_CaptainOrMember_OneOrOther unique( PersonID, TeamID, C_or_M );

create table Captains(
    PersonID  int not null,
    TeamID    int not null,
    C_or_M    char( 1 ) not null,
    ...,
    ...,    <Captain related data>
    ...,
    constraint PK_Captains primary key( PersonID, TeamID ),
    constraint CK_Captains_OneOrOther check( C_or_M = 'C' ),
    constraint FK_Captains_Captain foreign key( PersonID, TeamID, C_or_M )
        references CaptainOrMember( PersonID, TeamID, C_or_M )
);

create table Members(
    PersonID  int not null,
    TeamID    int not null,
    C_or_M    char( 1 ) not null,
    ...,
    ...,    <Member related data>
    ...,
    constraint PK_Members primary key( PersonID, TeamID ),
    constraint CK_Members_OneOrOther check( C_or_M = 'M' ),
    constraint FK_Members_Member foreign key( PersonID, TeamID, C_or_M )
        references CaptainOrMember( PersonID, TeamID, C_or_M )
);

如果表CaptainOrMember中的条目将特定人员定义为特定团队的队长,则该人员与该团队的组合无法插入到“成员”表中。它只能存在于Captains表中。反之亦然。