Общая таблица "один ко многим" для нескольких сущностей

Предположим, у меня есть две таблицы: «Клиент» и «Поставщик». Я хочу иметь общую адресную таблицу для адресов клиентов и поставщиков. У клиентов и поставщиков может быть от одного до нескольких адресов.

Опция 1

Добавьте столбцы для AddressID в таблицы Customer и Vendor. Мне это не кажется чистым решением.

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

Я также видел это - только 1 столбец внешнего ключа в таблице адресов с другим столбцом, чтобы определить, к какой таблице внешних ключей принадлежит адрес. Мне этот не нравится, потому что он требует, чтобы все таблицы внешних ключей имели одинаковый тип идентификатора. Это также кажется беспорядочным, когда вы начинаете кодировать против него.

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

Итак, я слишком разборчив или есть что-то, о чем я не подумал?


person BenV    schedule 19.05.2010    source источник


Ответы (4)


Я бы сказал, что недостающий фрагмент головоломки - это отношение «есть», которое часто упускается из виду при моделировании данных; это отличается от знакомого отношения «имеет». Отношение «есть» похоже на отношение наследования в объектно-ориентированном дизайне. Чтобы смоделировать это, вам понадобится базовая таблица, которая представляет общие атрибуты поставщиков и клиентов. Например, мы могли бы назвать базовую таблицу «Организации»:

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

В этом примере «Поставщик» - это организация, а «Заказчик» - «организация, а у организации« есть »адрес. Таблицы "Организации", "Поставщики" и "Клиенты" имеют общий ключ и общую последовательность ключей, обеспечиваемую ссылочной целостностью.

person Paul Keister    schedule 20.05.2010
comment
+1 для аналогии с ОО. Я все думал, что это очень простая проблема наследования в объектно-ориентированном стиле, но я не знал, как смоделировать ее в модели данных. Думаю, я смогу объединить ваше решение с решением Энди Уайта и придумать отношения «один ко многим», которые я ищу. - person BenV; 20.05.2010

Я думаю, что из трех вариантов, которые вы указали, я был бы наиболее склонен выбрать вариант 1. Обычно у клиента или поставщика не более нескольких разных адресов, но если они есть, возможно, решение, приведенное ниже, будет работать лучше. для тебя. Я бы не стал выбирать вариант 2, потому что, вероятно, нет смысла связывать адрес и с покупателем, и с продавцом одновременно. Я знаю, что вы, вероятно, зададите только один из этих идентификаторов за раз, но модель может сбивать с толку, и вам может потребоваться добавить специальную логику, чтобы убедиться, что для любой данной записи установлен только 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)
person Andy White    schedule 19.05.2010

Как насчет четырех таблиц, одна из которых служит шлюзом для адресов? Так что у вас будет

Customer
    customerId (PK)
    addressBookId (FK to AddressBook)

Vendor
    vendorId (PK)
    addressBokId (FK to AddressBook)

AddressBook
    addressBookId (PK)

Address
    addressId (PK)
    addressBookId (FK to AddressBook)
person Andreas Andreou    schedule 07.08.2016

Можете ли вы изменить дизайн таблицы, чтобы в ней были следующие поля:

 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)

или у вас может быть две таблицы:

  • Address table, where no reference to types of address it is. i.e. to have both
    • entity ID (key)
    • Адрес
  • address type table, where it would point at entry and have the flag outside the table to have:
    • entity ID (FK to entity ID in the above table)
    • тип организации (покупатель или поставщик)
person A.Rashad    schedule 19.05.2010
comment
Это мой вариант 3. Вы объяснили это лучше, чем я. Я все еще хочу этого избежать. - person BenV; 19.05.2010
comment
кодирование можно упростить, если использовать в качестве фильтра флаг типа адреса. и вы можете гарантировать уникальность, используя совокупный ключ как для флага, так и для идентификатора. но если вы пытаетесь найти четвертое решение, найдите измененный ответ выше - person A.Rashad; 19.05.2010