Таблицы, которые «расширяют» другие таблицы

#sql-server #database-design

#sql-server #база данных-дизайн

Вопрос:

У меня есть таблица, в которой хранится информация о вызываемых поставщиках dbo.Vendor . В нем есть такие поля, как это:

  1. VendorID
 2. VendorName
 3. VendorType
 4. AddressLine1
 5. EMail
 6. Telephone
 7. and so on....
  

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

Действительно ли мне нужно создавать уникальную таблицу для каждого из этих разных поставщиков, например, dbo.VendorLaw , dbo.VendorCinema . Или я могу создать все возможные поля в основной dbo.Vendor таблице и оставить NULL значения, где поле не применяется к этому поставщику? Это, конечно, нарушает правила нормализации.

Ответ №1:

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

 CREATE TABLE schema.VendorAdditionalInfo (
   autoId serial NOT NULL,
   vendorId int,
   vendorInfoId int,
   vendorInfoText varchar
);
  

Затем создайте свою справочную таблицу:

 CREATE TABLE schema.VendorInfo (
   vendorInfoId serial NOT NULL,
   vendorType int,
   vendorInfoName text
)
  

Таким образом, вы можете создавать любое количество записей в VendorAdditionalInfo в зависимости от типа поставщика.

РЕДАКТИРОВАТЬ: Пример информации, которую вы вводите:

 INSERT INTO schema.VendorInfo (vendorType, vendorInfoName)
VALUES 
(1, 'Lawyer Registration Number'),
(2, 'Nurse ID Number'),
(3, 'Hot Dog Business License')
  

Затем для вашей таблицы записей вы бы ввели свою информацию как таковую:

 INSERT INTO schema.VendorAdditionalInfo (vendorId, vendorInfoId, vendorInfoText)
VALUES
(10, 1, 'LAW13245'),
(11, 2, 'NURSE234234'),
(12, 1, 'LAW56156'),
(13, 3, 'HOTDOGBUSINESSLIC23')
  

По сути, текстовое поле — это поле, уникальное для каждого дополнительного типа информации.

Комментарии:

1. Вау, это на самом деле очень умно. могу ли я спросить, для чего предназначено поле » vendorInfoText » в первой таблице?

2. Это будет включать значения дополнительной информации, которая вам требуется. Я обновил свой ответ, чтобы он был немного более понятным и показывал примеры вставки.

3. Единственная проблема, которую я вижу в связи с этим, заключается в том, что vendorInfoText будет содержать значения одного и того же типа данных. Я не могу указать разные типы данных для каждого из дополнительных полей. Может ли это вызвать проблему масштабируемости, учитывая, что количество поставщиков, вероятно, вырастет до сотен тысяч?

4. Это ограничение; можете ли вы привести примеры, отличные от регистрационных номеров?

5. Это называется моделью вложенного значения объекта (EAV). Это хорошо известно, и ведется много дискуссий о том, хорошая это идея или нет. Это сводится к балансированию между удобством обслуживания (EAV) и производительностью (иметь миллион столбцов в одной строке). В любом случае код вашего приложения должен знать о конкретных полях для определенных типов поставщиков. en.wikipedia.org/wiki /…

Ответ №2:

Я бы создал дополнительные таблицы. Это позволяет вам легко применять ограничения null / ненулевые (и другие) на основе типа поставщика — и вы даже можете создать суперключ в существующей таблице on (VendorID,VendorType) и вычисляемый столбец в каждом столбце, определяемом для конкретного поставщика, чтобы гарантировать, что, например, только поставщики кинотеатров имеют записи в таблице VendorCinema.

 CREATE TABLE Vendors (
   VendorID int IDENTITY(-47,1) not null,
   VendorName varchar(19) not null,
   VendorType varchar(11) not null,
   AddressLine1 varchar(35) not null,
   EMail varchar(312) null,
   Telephone varchar(15) null,
   constraint PK_Vendors PRIMARY KEY (VendorID),
   constraint UQ_Vendor_Types UNIQUE (VendorID,VendorType),
   constraint CK_Vendor_Types CHECK (VendorType in ('Law','Cinema'))
  

)

и

 CREATE TABLE CinemaVendors (
    VendorID int not null,
    VendorType as CONVERT(varchar(11),'Cinema') persisted,
    Seating int not null,
    BruceWillisMovies int not null,
    constraint PK_CinemaVendors PRIMARY KEY (VendorID),
    constraint FK_CinemaVendors_Vendors FOREIGN KEY
                                (VendorID,VendorType)
             references Vendors (VendorID,VendorType),
    constraint CK_BruceWillisMovies CHECK (BruceWillisMovies > 3)
)
  

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

Это также устраняет проблемы с моделью EAV — там, где мы хотим int сохранить для поставщиков кинотеатров, мы уверены, что int действительно был сохранен.

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

Комментарии:

1. Это работает, но теперь, как мне написать SQL-запрос, чтобы выбрать все из Vendors таблицы, а затем выбрать все из CinemaVendors , только если VendorType это «Cinema»? Придется ли мне писать различные инструкции IF ELSE, чтобы охватить все возможные типы поставщиков?

2. Просто для добавления я могу передать только VendorID в качестве критерия поиска с веб-сайта.

3. Вы подключаетесь к поставщикам с помощью XVendors, чтобы получить всю информацию о XVendor. В контексте конкретного X вы используете его таблицу. Вам нужно выполнять ветвление / регистр для Vendor VendorType только тогда, когда вы делаете что-то конкретное для X при обработке всех поставщиков.

4. Значит, ЛЕВОЕ СОЕДИНЕНИЕ выполняется полностью во всех таблицах XVendor?

5. ЛЕВОЕ СОЕДИНЕНИЕ добавляет нули для не совпадающих значений. Вам нужна куча строк с идентификаторами поставщиков, отличными от XVendor, плюс нули?