我正在规划数据库架构,并且我遇到了一个我不知道最佳方法的情况。我真的在寻找我提出的每个解决方案的优缺点列表,也许后面会推荐符合最佳数据库实践的建议。
所以,问题是我有两个实体,它们之间有多个多对多关系。这两个表是团队和人;团队由许多人组成,一个人可以在团队中拥有一个或多个角色。角色包括团队领导,团队成员,团队追随者等。一个人可能有一个以上的角色为特定团队,但理想情况下这些角色的一部分是互斥的,而其他角色则不是。
以下是我考虑过的解决方案:
1)为每个角色创建一个单独的联结表。每个表中存在一行表示一个人属于一个团队,特定表表示该团队中的人员角色。必须在应用程序级别强制执行互斥角色。
2)创建单个联结表并在该表上存储枚举以指定人员具有的角色。给定的人员 - 团队组合可能在此表中有多行,每个人对该团队的每个角色都有一行。必须在应用程序级别强制执行某些角色的相互排他性。
3)创建一个联结表,并在表上存储一个布尔标志列表,每个角色一个。每个人员 - 团队组合在表中都有一行,并且标志确定用户在该团队中具有哪些角色。可以在数据库级别强制执行相互排他性,因为所有互斥角色可以共享表中的单个枚举字段。
4)创建两个联结表。这是(2)和(1)的组合,允许在数据库级别强制执行互斥。将有一个联结表,其中包含用于互斥角色的枚举,另一个联结表(具有枚举)将处理所有非独占角色。
我有什么遗忘的吗?哪个选项看起来最自然?
由于
答案 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表中。反之亦然。