【问题标题】:Multiple Junction Tables Between Same Entities相同实体之间的多个连接表
【发布时间】:2015-05-09 13:10:21
【问题描述】:

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

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

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

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

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

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

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

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

谢谢

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 2020-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多