0

想象一下,我有一个名为offers. offers可以从多个表中引用,例如purchase,membership等。请注意,将来可以引用更多表。

购买和会员资格已经存在于数据库中,它们将始终在相应的报价对象之前创建。可以将其想象为购买 X 可能会提供报价 Y(一对一)

为了在关系模式中实现这一点,我想到了两种可能的选择。

选项1

offers表不会有任何引用。相反,purchasetable 和membershiptable 将有一个名为offer_id引用该offer表的列。如下所示

   table offers { 
      id,
      offer_name, 
   }

   table purchase { 
      id,
      ..other fields,
      offer_id fk(offers),
   }

   table membership { 
      id,
      ..other fields,
      offer_id fk(offers),
   }

选项 2

offers表将包含一个type引用商品类型的字段(purchasemembership等),并且将有多个可以为空的外键引用每个表。

   table offers { 
      id,
      offer_name, 
      type enum(purchase, membership,
      purchase_id fk(purchases) NULL, 
      membership_id fk(memberships) NULL,
   }

   table purchase { 
      id,
      ..other fields,
   }

   table membership { 
      id,
      ..other fields,
   }

我觉得选项 1 是最简单的方法,也是正确的方法。但这感觉就像违背了数据库设计原则(父母不应该提及孩子等)。

正确的方法应该是什么?如果我选择选项 1,会出现什么问题?

4

1 回答 1

1

由于您在oroffer实体之后创建实体,因此它是子实体,因此应该具有父表的外键。purchasemembershipoffer

我知道反过来这样做很诱人,但是语义在数据库设计中很重要:

  1. 如果您的 FK 在父实体中,那么您将面临不属于任何实体的孤儿报价的风险。您无法通过 FK 强制执行完整性。
  2. 您无法通过标准数据库技术防止将 1 个商品分配给多个实体。您需要编写额外的应用程序代码来强制执行此规则。
  3. 任何查看您的 ERD 的人都会对关系的性质得出错误的初步结论,因此您必须向每位新同事提供额外的解释。
  4. 如果您在数据库模式之上使用 ORM,ORM 将再次错误地解释关系,在 FK 之后设置类和关系。同样,需要额外的解释。

您可以通过三个选项来设计表中的外键offer以遵循选项 2:

  1. 每个父级都有一个单独的 FK 字段。优点是孩子所属的父实体一目了然,并且易于实施参照完整性。缺点是您需要创建与父实体一样多的字段,并且需要更改表来添加新表。如果您的父实体数量有限且稳定,则效果很好。
  2. 使用 atypeparent_id字段组合。类型字段告诉您记录属于哪个父级。这与之前的解决方案相反——灵活地添加新的父类型,但通过数据库工具强制引用完整性并不简单!
  3. 为每个父类型使用单独的报价表。如果您计划按类型区分各种优惠,此设计可能很有用。
于 2020-10-08T12:47:04.720 回答