Я часто сталкиваюсь с ситуацией в базе данных, когда заданная таблица может быть привязана к одной из нескольких родительских таблиц. Я видел два решения этой проблемы, но ни одно не удовлетворяет лично. Мне любопытно, какие другие модели вы видели там? Есть ли лучший способ сделать это?
Придуманный пример
Допустим, моя система имеет Alerts
. Оповещения могут быть получены для различных объектов - клиентов, новостей и продуктов. Данное предупреждение может быть только для одного элемента. По какой-либо причине Клиенты, Статьи и Продукты быстро перемещаются (или локализуются), поэтому необходимый текст / данные не могут быть добавлены в Оповещения при создании Оповещения. Учитывая эту настройку, я видел два решения.
Примечание: ниже DDL для SQL Server, но мой вопрос должен быть применим к любой СУБД.
Решение 1 - Многочисленные клавиши с возможностью обнуления
В этом решении таблица, которая ссылается на одну из множества таблиц, имеет несколько столбцов FK (для краткости ниже DDL не показывает создание FK). ХОРОШО - В этом решении приятно, что у меня есть внешние ключи. Нулевая возможность FK делает это удобным и относительно простым для добавления точных данных. ПЛОХИЕ Запросы не велики, потому что для получения соответствующих данных требуются операторы N LEFT JOINS или N UNION. В SQL Server, в частности, LEFT JOINS исключают создание индексированного представления.
CREATE TABLE Product (
ProductID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
CONSTRAINT PK_Product Primary Key CLUSTERED (ProductID)
)
CREATE TABLE Customer (
CustomerID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
CONSTRAINT PK_Customer Primary Key CLUSTERED (CustomerID)
)
CREATE TABLE News (
NewsID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
CONSTRAINT PK_News Primary Key CLUSTERED (NewsID)
)
CREATE TABLE Alert (
AlertID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
ProductID int null,
NewsID int null,
CustomerID int null,
CONSTRAINT PK_Alert Primary Key CLUSTERED (AlertID)
)
ALTER TABLE Alert WITH CHECK ADD CONSTRAINT CK_OnlyOneFKAllowed
CHECK (
(ProductID is not null AND NewsID is null and CustomerID is null) OR
(ProductID is null AND NewsID is not null and CustomerID is null) OR
(ProductID is null AND NewsID is null and CustomerID is not null)
)
Решение 2. Один FK в каждой родительской таблице.
В этом решении каждая «родительская» таблица имеет FK для таблицы предупреждений. Это позволяет легко получать оповещения, связанные с родителем. С другой стороны, нет никакой реальной цепочки от оповещения о том, кто ссылается. Кроме того, модель данных допускает сиротские оповещения, когда оповещение не связано с продуктом, новостями или клиентом. Опять же, несколько левых соединений, чтобы выяснить связь.
CREATE TABLE Product (
ProductID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
AlertID int null,
CONSTRAINT PK_Product Primary Key CLUSTERED (ProductID)
)
CREATE TABLE Customer (
CustomerID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
AlertID int null,
CONSTRAINT PK_Customer Primary Key CLUSTERED (CustomerID)
)
CREATE TABLE News (
NewsID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
Name varchar(100) not null
AlertID int null,
CONSTRAINT PK_News Primary Key CLUSTERED (NewsID)
)
CREATE TABLE Alert (
AlertID int identity(1,1) not null,
CreateUTC datetime2(7) not null,
CONSTRAINT PK_Alert Primary Key CLUSTERED (AlertID)
)
Это просто жизнь в базе данных отношений? Есть ли альтернативные решения, которые вы нашли более удовлетворяющими?
Alertable
. Что имеет смысл?