Как применить подтипы в базе данных SQL Server? - PullRequest
11 голосов
/ 09 октября 2010

Я работаю над программой, в которой вы можете регистрировать жалобы.Существует три типа жалоб: internal (ошибки от сотрудников), external (ошибки от другой компании) и supplier (ошибки, сделанные поставщиком).Они содержат разные данные, которые не могут быть переданы.В настоящее время у меня есть 4 таблицы (жалоба, сотрудник, компания и поставщик).Вот визуализация таблиц:

У меня есть базовое понимание подтипов, но я не могу перевести их из ERD в реальную базу данных SQL Server или, по крайней мере, в этом сценарии.Примерно так выглядят 4 таблицы (нерелевантные атрибуты опущены):

Жалоба
Жалоба PK

Сотрудник
EmployeeId PK
EmployeeName

Company
CompanyId PK
CompanyName

Supplier
SupplierId PK
SupplierName

При регистрации жалобы ошибка совершается одним из трех типов, и все они хранят различную информацию.Каков наилучший способ хранения информации в этом случае?Я подумал о том, чтобы поместить 2 дискриминатора в таблицу жалоб: ComplaintType и Id, чтобы я мог указать, какую таблицу проверять и какой идентификатор мне нужен, но это не очень чисто и не эффективно.

Пожалуйста помогите.

Ответы [ 5 ]

18 голосов
/ 09 октября 2010

См. Несколько действительно полезных ресурсов по теме:

Существует три основных подхода:

  • Таблица на подкласс
  • Таблица на иерархию
  • Таблица на конкретный тип

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

4 голосов
/ 09 октября 2010

Я настоятельно рекомендую вам НЕ использовать метод "2 дискриминатора". У вас фактически будет столбец внешнего ключа, который указывает на одну из трех таблиц, в зависимости от поля ComplaintType. Если вы сделаете это, вы будете обходить проверки ссылочной целостности, предоставляемые SQL Server, и все преимущества, которые предоставляются с внешними ключами. На моей предыдущей работе была таблица EntityTypeIndexLabel, которая представляла собой «таблицу мостов», которая связывала IndexLabels (в основном метаданные) с различными «сущностями», которые представляли собой множество различных потенциальных таблиц (Document, Binder, Workflow и т. Д.) Это было просто ужасно. ФК в этой таблице может указывать на множество разных таблиц. Осиротевшие записи могли появляться везде. Для определения таблицы, к которой нужно присоединиться, должна быть реализована дополнительная логика. В общем, объединение было трудной задачей. Это были все виды головной боли.

Я думаю, что у вас есть два варианта:

-3 столбца в жалобе: EmployeeComplaintID, CompanyComplaintID, SupplierComplaintID. Идентификаторы жалоб должны быть уникальными во всех таблицах (представьте здесь GUID, а не столбцы IDENTITY). В каждой строке в Жалобе будет заполнен только один из этих идентификаторов, остальные два будут пустыми. Затем вы можете просто НАСТРОИТЬ ВНУТРЕННЕЕ СОЕДИНЕНИЕ с этими таблицами в каждом запросе, чтобы получить необходимые данные.

- Одна гигантская таблица со всеми возможными полями, необходимыми для каждого типа жалобы, с установкой неиспользуемых полей других типов жалобы в NULL.

1 голос
/ 05 сентября 2014

В ответ на ваш комментарий о принятом ответе:

Ниже представлен способ проверки, чтобы убедиться, что только один из трех ключей имеет данные:

alter table complaint_master 
    add constraint loc_attribute_has_one_value 
    check ( 
        (case when complaint_employee is null then 0 else 1 end) + 
        (case when complaint_supplier is null then 0 else 1 end) + 
        (case when complaint_external is null then 0 else 1 end)  = 1 
    ); 
1 голос
/ 09 октября 2010

У вас может быть жалоба SubTypeID с отношением FK к PK всех трех ваших таблиц подтипа: сотрудник, компания и поставщик.

1 голос
/ 09 октября 2010

Является ли основной проблемой то, что вам нужен своего рода «серийный номер», чтобы однозначно идентифицировать жалобу независимо от того, какой тип? По сути, вам нужна таблица для каждого типа жалобы (как я думаю, у вас будет), а также основная таблица «Жалоба» с ComplaintId. Каждая из таблиц конкретного типа будет иметь внешний ключ для Complaint.ComplaintId. Может оказаться полезным иметь поле «тип» в «Жалобе», но на самом деле это не требуется для модели.

...