Внешний ключ к одной из многих таблиц (MySQL)

#mysql #database #database-design

#mysql #База данных #база данных-дизайн

Вопрос:

Я разрабатываю веб-сайт для малого бизнеса (озеленение, удаление деревьев и т. Д.), принадлежащего члену семьи. Это своего рода любимый проект.

Веб-сайт позволит пользователям создавать учетную запись, а затем запрашивать услуги и создавать необходимые счета-фактуры, но также позволит члену моей семьи вводить счета-фактуры за заказы, не полученные через веб-сайт.

Я работаю над базой данных (MySQL), и в настоящее время это то, что у меня есть. Все, что содержит «User», относится к онлайн-клиентам, а все, что содержит Cust, относится к не онлайн-клиентам.

В основном то, что я пытаюсь сделать здесь, это:

У счета-фактуры есть клиент, бизнес или пользователь (онлайн-клиент). Счет-фактура также содержит одну или несколько строк счета, и каждая строка счета содержит услугу или продукт.

Я помещаю пользователей (онлайн-клиентов) в отдельную таблицу, потому что для пользователя имеет смысл иметь пароль и соль пароля (и, возможно, другие вещи), но у клиента, добавленного исключительно для ведения записей, не должно быть пароля и вещей, связанных с веб-сайтом.

    ServicesAndProducts 
--------------------------
| ID INT (PK)            | 
| Name VARCHAR(50)       |  
| BasePrice DECIMAL(7,2) |
| ...                    |
--------------------------

   CustServicesProvided               UserServicesProvided
---------------------------       ---------------------------
| ID INT (PK)             |       | ID INT (PK)             |
| ServiceID INT (FK)      |       | ServiceID INT (FK)      |
| CustInvoiceID INT (FK)  |       | UserInvoiceID INT (FK)  |
| ...                     |       | ...                     |
---------------------------       ---------------------------

       CustInvoices                     UserInvoices
--------------------------        --------------------------
| ID INT (PK)            |        | ID INT (PK)            |
| CustomerID INT (FK)    |        | UserId INT (FK)        |
| ....                   |        | ....                   |
--------------------------        --------------------------

        Customers                           Users
--------------------------        ---------------------------
| ID INT (PK)            |        | ID INT (PK)             |
| Name VARCHAR(50))      |        | Name VARCHAR(50)        |
| BasePrice DECIMAL(7,2) |        | PasswordHash VARCHAR(50)|
| ...                    |        | PasswordSalt VARCHAR(50)|
--------------------------        | ...                     |
                                  ---------------------------
 

У меня также есть другие похожие сервисы BusinessServicesProvided, BusinessInvoices и Business, потому что мне нужны внешние ключи, и у предприятий будут другие поля, чем у двух других.

Мой вопрос: есть ли способ объединить таблицы счетов-фактур вместе и объединить таблицы предоставляемых услуг вместе, сохраняя при этом три вида внешних ключей между таблицей счетов-фактур и клиентами и пользователями (и предприятиями)?

Я подумал о возможном добавлении таблицы InvoiceType, а затем о том, чтобы указать TypeID (FK) в таблице счетов, но я не знаю, как поддерживать внешний ключ между объектом (клиентом, бизнесом или пользователем) и счетом. например:

    ServicesAndProducts 
--------------------------
| ID INT (PK)            | 
| Name VARCHAR(50)       |  
| BasePrice DECIMAL(7,2) |
| ...                    |
--------------------------

      ServicesProvided    
---------------------------
| ID INT (PK)             |
| ServiceID INT (FK)      |
| CustInvoiceID INT (FK)  |
| ...                     |
---------------------------

       Invoices                            InvoiceType
--------------------------        ---------------------------
| ID INT (PK)            |        | ID INT (PK)             |
| ForeignID INT (FK)     |        | Name VARCHAR(50)        |
| Invoice Type INT (FK)  |        |                         |
| ....                   |        |                         |
--------------------------        ---------------------------

        Customers                           Users
--------------------------        ---------------------------
| ID INT (PK)            |        | ID INT (PK)             |
| Name VARCHAR(50))      |        | Name VARCHAR(50)        |
| BasePrice DECIMAL(7,2) |        | PasswordHash VARCHAR(50)|
| ...                    |        | PasswordSalt VARCHAR(50)|
--------------------------        | ...                     |
                                  ---------------------------
 

Я также рассматривал возможность создания триггера для создания нового клиента при создании пользователя, но я также хотел бы, чтобы клиент мог просматривать счета / услуги, которые они запрашивали в прошлом.

Это мой первый опыт проектирования базы данных, поэтому любые идеи приветствуются.

Ответ №1:

Нет, вы не можете указывать внешний ключ на первичные ключи в разных таблицах, указывая базе данных найти соответствующую запись в одной из таблиц (кроме того, предположительно диапазон значений первичного ключа в разных таблицах может перекрываться, и тогда вы можете сопоставить две или более таблиц первичных ключей).

Ваша ошибка заключается в создании совершенно новой таблицы для учета различий, например, между клиентами и пользователями. Вместо этого создайте единую таблицу с общими столбцами (вероятно, называемую customer), а затем разделите таблицы с внешними ключами обратно в основную таблицу. Каждая таблица содержит столбцы для одного из подтипов клиентов (онлайн или из плоти и крови).

То же самое для разных видов счетов. Одна таблица содержит общую информацию о счете (особенно первичный ключ), а одна или несколько вспомогательных таблиц содержат информацию, относящуюся к виду счета.

Этот дизайн похож на наследование классов в объектно-ориентированном программировании.