1

我正在计划一个数据库模式,但我遇到了一种情况,我不知道最好的方法。我真的在寻找我提出的每个解决方案的优缺点列表,然后可能会给出符合最佳数据库实践的建议。

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

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

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

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

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

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

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

谢谢

4

2 回答 2

1

您偶然发现了派对模型!:)

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

与角色相同。除非它变得笨拙,否则将它们存储在一张表中。

如果你使用像 hibernate 这样的 ORM 来更新你的数据库模式,如果你愿意,它可以很容易地切换到类表继承。我想说 STI 在开发过程中更容易使用。

于 2015-05-09T18:48:57.673 回答
1

每个表 People 和 Team 代表实体。交集或联结表各自代表实体之间的关系。如果您有多个可能的关系,那么拥有多个联结表是有意义的。

您暗示某些关系可能是相互排斥的。这是一个足够简单的问题来解决。

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”指定。因此,一个人可以是队长或团队成员,但不能两者兼而有之。

它具有将一个联结表用于两个关系的额外优势。

也就是说,除非您有一些仅船长和仅会员数据要添加到关系元组中。然后您可以添加两个“子联结”表。在这里他们是为了说明。

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 表中的条目将特定人员定义为特定团队的队长,则该人员和该团队的组合不能插入到Members 表中。它只能存在于 Captains 表中。反之亦然。

于 2015-05-10T05:30:04.903 回答