Введение супертипов и подтипов
Я предлагаю вам использовать супертипы и подтипов.Во-первых, создать PartyType
и Party
таблицы:
CREATE TABLE dbo.PartyType (
PartyTypeID int NOT NULL identity(1,1) CONSTRAINT PK_PartyType PRIMARY KEY CLUSTERED
Name varchar(32) CONSTRAINT UQ_PartyType_Name UNIQUE
);
INSERT dbo.PartyType VALUES ('Person'), ('Business');
Supertype
CREATE TABLE dbo.Party (
PartyID int identity(1,1) NOT NULL CONSTRAINT PK_Party PRIMARY KEY CLUSTERED,
FullName varchar(64) NOT NULL,
BeginDate smalldatetime, -- DOB for people or creation date for business
PartyTypeID int NOT NULL
CONSTRAINT FK_Party_PartyTypeID FOREIGN KEY REFERENCES dbo.PartyType (PartyTypeID)
);
подтипы
Затем, если есть столбцы, которые являются уникальными для человека, создать Person
таблицу с только те:
CREATE TABLE dbo.Person (
PersonPartyID int NOT NULL
CONSTRAINT PK_Person PRIMARY KEY CLUSTERED
CONSTRAINT FK_Person_PersonPartyID FOREIGN KEY REFERENCES dbo.Party (PartyID)
ON DELETE CASCADE,
-- add columns unique to people
);
И если есть столбцы, которые являются уникальными для бизнеса, создать Business
таблицу только те:
CREATE TABLE dbo.Business (
BusinessPartyID int NOT NULL
CONSTRAINT PK_Business PRIMARY KEY CLUSTERED
CONSTRAINT FK_Business_BusinessPartyID FOREIGN KEY REFERENCES dbo.Party (PartyID)
ON DELETE CASCADE,
-- add columns unique to businesses
);
Использование и примечания
Наконец, ваша Asset
таблица будет выглядеть примерно так:
CREATE TABLE dbo.Asset (
AssetID int NOT NULL identity(1,1) CONSTRAINT PK_Asset PRIMARY KEY CLUSTERED,
PartyID int NOT NULL
CONSTRAINT FK_Asset_PartyID FOREIGN KEY REFERENCES dbo.Party (PartyID),
AssetTag varchar(64) CONSTRAINT UQ_Asset_AssetTag UNIQUE
);
Взаимосвязь между партийным столом супертипа с подтипом ta bles Business и Person - «один к нулю или один». Теперь, в то время как подтипы обычно не имеют соответствующей строки в другой таблице, в этой конструкции есть возможность иметь Сторону, которая заканчивается в обеих таблицах. Однако вам действительно может понравиться следующее: иногда человек и бизнес почти взаимозаменяемы. Если это не полезно, в то время как триггер для принудительного выполнения этого будет довольно легко выполнен, лучшим решением является, вероятно, добавить столбец PartyTypeID
в таблицы подтипов, сделав его частью PK & FK и положив ограничение CHECK на PartyTypeID
.
Красота этой модели заключается в том, что, когда вы хотите создать столбец, который имеет ограничение для бизнеса или человека, вы создаете ограничение для соответствующей таблицы вместо таблицы сторонних участников.
Кроме того, при желании может оказаться полезным включение каскадного удаления в ограничениях, а также триггер INSTEAD OF DELETE
в таблицах подтипов, которые вместо этого удаляют соответствующие идентификаторы из таблицы супертипов (это не гарантирует, что строки супертипа, которые не имеют подтипа строки присутствуют). Эти запросы очень просты и работают на уровне всей строки-существующего или не существующего уровня, что, на мой взгляд, является гигантским улучшением по сравнению с любым проектом, который требует проверки согласованности столбцов.
Также обратите внимание, что во многих случаях столбцы, которые, по вашему мнению, должны идти в одной из таблиц подтипов, действительно могут быть объединены в таблицу супертипов, например номер социального страхования. Назовите это TIN (идентификационный номер налогоплательщика), и он работает как для бизнеса, так и для людей.
ID Колонка Именование
Вопрос о том, стоит ли называть столбец в таблице Person PartyID
, PersonID
или PersonPartyID
твой собственные предпочтения, но я думаю, что лучше назвать их PersonPartyID
или BusinessPartyID
- терпимости к стоимости более длинного имени, это позволяет избежать двух типов путаницы. Например, кто-то, незнакомый с базой данных, видит BusinessID
и не знает, что это PartyID
или видит PartyID
и не знает, что он ограничен внешним ключом только в таблице Business
.
Если вы хотите создать представления для таблиц Party
и Business
, они даже могут быть материализованные представления, так как это просто внутреннее соединение, и вы могли переименовать PersonPartyID
столбец PersonID
, если вы действительно были так склонны (хотя Я бы не стал). Если это имеет большое значение для вас, вы можете даже активировать триггеры INSTEAD OF INSERT
и INSTEAD OF UPDATE
для этих представлений, чтобы обрабатывать вставки для двух таблиц для вас, чтобы представления отображались полностью как их собственные таблицы для многих прикладных программ.
Создание Вашего Предполагаемого Проектные работы как есть
Кроме того, я не хочу говорить об этом, но если вы хотите иметь ограничение в вашей предлагаемой конструкции, что обеспечивает соблюдение только один столбец заполняется, вот код для этого:
ALTER TABLE dbo.Assets
ADD CONSTRAINT CK_Asset_PersonOrBusiness CHECK (
CASE WHEN PersonID IS NULL THEN 0 ELSE 1 END
+ CASE WHEN BusinessID IS NULL THEN 0 ELSE 1 END = 1
);
Однако, я не рекомендую это решение.
Заключительные мысли
Естественным третьего подтипа добавить является организация, в смысле чего-то, что люди и предприятия могут иметь членство в. Supertype и подтипа также элегантно решить клиентов/сотрудников, клиентов/поставщика, и другие проблемы, аналогичные тем, которые вы представили.
Будьте осторожны, чтобы не путать «Is-A» с «Acts-As-A». Вы можете сказать, что участник - это клиент, заглядывая в таблицу заказов или просматривая счет заказа, и может вообще не нуждаться в таблице Customer. Также не путайте идентичность с жизненным циклом: прокат автомобиля может быть в конечном итоге продан, но это прогресс в жизненном цикле, и его следует обрабатывать с данными столбцов, а не с таблицей - автомобиль не начинается как RentalCar
и получить превратился в ForSaleCar
позже, это автомобиль все время. Или, возможно, RentalItem
, может быть, в этом бизнесе тоже будут арендовать другие вещи. Вы поняли эту идею.
Возможно, нет необходимости иметь таблицу PartyType
. Тип партии может определяться наличием строки в соответствующей таблице подтипов. Это также позволило бы избежать потенциальной проблемы PartyTypeID
, не соответствующей присутствию таблицы подтипов. Одна из возможных реализаций заключается в том, чтобы сохранить таблицу , но удалите PartyTypeID
из таблицы Party, затем в представлении таблицы Party верните правильное значение PartyTypeID
, на основании которого в таблице подтипов имеется соответствующая строка. Это не будет работать, если вы решите разрешить сторонам быть оба подтипами. Затем вы просто придерживаетесь подтипов и знаете, что то же значение BusinessID
и PersonID
ссылаются на эту же сторону.
Дальнейшее чтение На этой Pattern
Пожалуйста см A Universal Person and Organization Data Model для более полного и теоретической обработки.
Недавно я нашел следующие статьи полезными для описания некоторых альтернативных подходов к моделированию наследования в базе данных.Хотя специфичные для инструмента Entity Framework ОРМ Microsoft, нет никаких причин, вы не могли бы реализовать эти сами в любом развитии БД:
P.S. Я неоднократно менял свое мнение о столбце, обозначающем идентификаторы в таблицах подтипов, из-за того, что у меня больше опыта на моем поясе.
Мне нужно набрать быстрее ... когда я начал свой ответ, только HLGEM опубликовал. Sigh. – ErikE
Вы набрали много. Я удаляю свой пост из уважения, насколько хорошо вы объяснили дизайн схемы базы данных. –
Это было очень подумал о вас! – ErikE