Как применить подтипы в базу данных SQL Server?
-
28-09-2019 - |
Вопрос
Я работаю над программой, в которой вы можете зарегистрировать жалобы. Есть три типа жалоб: internal
(Ошибки от сотрудников), external
(ошибки от другой компании) и supplier
(Ошибки, сделанные поставщиком). Они держат разные данные, которые не могут быть разделены. У меня в настоящее время 4 столы (жалоба, сотрудника, компания и поставщик). Вот визуализация таблиц:
У меня есть базовое понимание подтипов, но я не могу перевести их из ERD в реальную базу данных SQL Server или, по крайней мере, в этом сценарии. Это примерно так, как выглядят 4 таблицы (неактуальные атрибуты опущены):
Жалоба
Жалоба PK
Работник
Employeeeid pk
Имя сотрудника
Компания
CompanyID PK.
Название компании
Поставщик
Приложение PK.
Наименование поставщика
При регистрации жалобы ошибка допускается любым из 3 типов, и все они хранят разные информации. Как лучше всего хранить информацию в этом случае? Я подумал о том, чтобы поместить 2 дискриминатора в столовую жалобу: ComplaintType
и Id
Таким образом, я могу указать на какой стол, чтобы проверить, и какой идентификатор нужен, но это не очень чисто, ни эффективно.
Пожалуйста помогите.
Решение
Я настоятельно рекомендую вам не использовать метод «2 дискриминатора». Вы будете эффективно иметь столбец внешнего ключа, который указывает на одну из трех таблиц, в зависимости от поля ComEttyPE. Если вы это сделаете, вы будете передавать проверки ссылочной целостности, поставляемой SQL Server и все преимущества, которые поставляются с внешними ключами. На моей предыдущей работе был таблица под названием EntitytypeindexLabel, которая была «мостовой таблицей», которая присоединила indexLabels (в основном метаданные) к различным «объектам», которые были много разных потенциальных таблиц (документ, связующее, рабочий процесс и т. Д.). Это было просто ужасно. FK в этой таблице может указывать на многие разные таблицы. Орфатические записи могут всплывать повсюду. Дополнительная логика должна была быть реализована для определения того, на какой таблице присоединится. Присоединения были болью писать в целом. Это были все виды головной боли.
Я думаю, что ваши два варианта:
-3 колонны в жалобе: rameeeComplineaintID, CompanyComplaintID, поставщик Комплектурид. CELETIDS должны быть уникальными во всех таблицах (думайте, что GUID здесь вместо столбцов идентификации). Каждая строка в жалобе будет иметь только одну из этих удостоверенных личности, остальные два будут нулевыми. Затем вы можете просто оставить внешнее соединение в этих таблицах в каждом запросе, чтобы получить необходимые вам данные.
-One Гигантская таблица со всеми возможными полями, которые вам нужны для каждого типа жалоб, устанавливая неиспользуемые поля других типов жалоб в NULL.
Другие советы
Смотрите несколько действительно хороших ресурсов по теме:
- Реализация наследства таблицы в SQL Server
- Как моделировать наследование в базе данных
- Как вы эффективно моделируете наследование в базе данных?
В основном есть три известных подхода:
- Таблица на подкласс
- Таблица на иерархию
- Таблица на бетон
У каждого есть плюсы и минусы, сияют в какой-то ситуации и отстой в других - изучите ресурсы и посмотрите, какие из трех подходит для ваших нужд лучших.
Является ли основной проблемой, который вам нужен какой-то «серийный номер», чтобы уникально определить жалобу, независимо от того, какой тип? В основном, потом вам нужен стол для каждого типа жалобы (как у вас будет, я думаю), а также таблица Master «Жалоба» с жалобами. Каждый из таблиц, специфичных к типам будет иметь внешний ключ для Tellaint.comLaintID. Возможно, вам полезно иметь поле «тип» в жалобе, но это на самом деле не требуется для модели.
У вас может быть жалобы, с которыми сталкивается FK, отношение к PK всех трех ваших подтипов- сотрудника, компании и поставщика.
В ответ вам комментарий к принятому ответу:
Ниже приведен возможность проверить проверку, чтобы убедиться, что только один из трех клавиш имеет данные:
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
);