多个实体的通用一对多表

时间:2010-05-19 04:46:07

标签: database database-design data-modeling

假设我有两个表,即客户和供应商。我想为客户和供应商地址提供一个公共地址表。客户和供应商都可以拥有一对多的地址。

选项1

将AddressID的列添加到CustomerVendor表中。这对我来说似乎不是一个干净的解决方案。

Customer     Vendor         Address
--------     ---------      ---------
CustomerID   VendorID       AddressID
AddressID1   AddressID1     Street
AddressID2   AddressID2     City...

选项2

将外键移动到Address表。对于客户,将填充Address.CustomerID。对于供应商,将填充Address.VendorID。我也不喜欢这样 - 每次我想将它用于另一个实体时,我都不需要修改地址表。

Customer     Vendor         Address
--------     ---------      ---------
CustomerID   VendorID       AddressID
                            CustomerID
                            VendorID

选项3

我也看到了这一点 - 在Address表上只有一个外键列,另一列用于标识该地址所属的外键表。我不喜欢这个,因为它要求所有外键表具有相同类型的ID。一旦你开始编码它,它似乎也很混乱。

Customer     Vendor         Address     
--------     ---------      ---------
CustomerID   VendorID       AddressID
                            FKTable
                            FKID

那么,我是否过于挑剔,或者有什么我没有想到的?

4 个答案:

答案 0 :(得分:8)

我想说这个难题的缺失部分是数据建模中经常被忽视的“是一种”关系;这与熟悉的“有”关系截然不同。 “是一种”关系类似于面向对象设计中的继承关系。要对此进行建模,您需要一个表格,代表供应商和客户的共同属性。例如,我们可以调用基表“组织”:

Organizations       Vendors               Customers
--------------      ---------------------  ---------------------
OrganizationID(PK)  OrganizationID(FK/PK)  OrganizationID(FK/PK)
AddressID1(FK)
AddressID2(FK)

在此示例中,供应商“是”组织,而“客户”是“组织,而组织”具有“地址”。 “组织”,“供应商”和“客户”表共享公用密钥和通过参照完整性强制执行的公用密钥序列。

答案 1 :(得分:6)

我认为,在您给出的三个选项中,我最倾向于使用选项1.通常,客户或供应商不会有多个不同的地址,但如果他们这样做,可能是以下解决方案会更好地为你工作。我不会选择选项2,因为将地址与客户和供应商同时关联可能没有意义。我知道您可能一次只设置其中一个ID,但模型可能会令人困惑,您可能需要添加特殊逻辑以确保在任何给定记录上只设置CustomerID或VendorID。我绝对不会做选项3,因为你不能让FKID成为真正的FK。如果希望列引用多个表,则无法在数据库中使用FK约束来强制执行该表。另外,如果您计划使用ORM在代码中与数据库进行交互,那么根据单独的“鉴别器”列,它们往往难以处理引用多个表的“假”外键。

如果您想要一个真正开放式的解决方案,您可以在客户和地址以及供应商和地址之间创建多对多关系。

Customer
--------
CustomerID (PK)

Vendor
------
VendorID (PK)

Address
-------
AddressID (PK)

CustomerAddress
---------------
CustomerID (FK/PK)
AddressID (FK/PK)

VendorAddress
-------------
VendorID (FK/PK)
AddressID (FK/PK)

答案 2 :(得分:1)

如果有四个表作为地址的网关? 所以你会有

Customer
    customerId (PK)
    addressBookId (FK to AddressBook)

Vendor
    vendorId (PK)
    addressBokId (FK to AddressBook)

AddressBook
    addressBookId (PK)

Address
    addressId (PK)
    addressBookId (FK to AddressBook)

答案 3 :(得分:0)

您可以重新设计表格以包含以下字段:

 Address_Type  (a flag to say that this is a customer, or a vendor)
 ID            (a common ID for both customer and vendor and depending on the flag you know what ID it is)
 Address       (Data of address itself)

或者你可以有两张桌子:

  • 地址表,其中没有对地址类型的引用。即两者兼而有之
    • 实体ID(密钥)
    • 地址
  • 地址类型表,它将指向入口并在表外具有以下标志:
    • 实体ID(FK到上表中的实体ID)
    • 实体类型(客户或供应商)