Я досить часто зустрічаю ситуацію в базі даних, коли дана таблиця може ФК перетворюватися на одну з кількох різних батьківських таблиць. Я бачив два рішення проблеми, але жоден не задовольняє особисто. Мені цікаво, які ще візерунки ви бачили там? Чи є кращий спосіб це зробити?
Надуманий приклад
Скажімо, моя система Alerts
. Сповіщення можна отримувати для різних об'єктів - клієнтів, новин та продуктів. Подане сповіщення може бути для одного і лише одного предмета. З будь-якої причини Клієнти, статті та продукти швидко рухаються (або локалізуються), тому необхідний текст / дані не можна втягувати в Сповіщення при створенні сповіщення. Враховуючи це налаштування, я бачив два рішення.
Примітка. Нижче розміщено DDL для SQL Server, але моє запитання має стосуватися будь-яких СУБД.
Рішення 1 - Кілька нульових FKeys
У цьому рішенні таблиця, що посилається на одну із багатьох таблиць, має кілька стовпців FK (задля стислості, нижче DDL не показує створення FK). ДОБРО - У цьому рішенні приємно, що у мене є іноземні ключі. Нульова оптимічність ФК робить це зручним і відносно простим додаванням точних даних. Запит BAD не є великим, оскільки для отримання супутніх даних потрібно 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 - по одному ФК у кожній батьківській таблиці
У цьому рішенні кожна «батьківська» таблиця має ФК до таблиці сповіщень. Це дозволяє легко отримувати сповіщення, пов’язані з батьком. З нижньої сторони немає реального ланцюга від Попередження до того, хто посилається. Крім того, модель даних передбачає можливість осиротіти оповіщення - де попередження не пов’язане з товаром, новинами чи замовником. Знову ж таки, декілька лівих приєднується, щоб з’ясувати асоціацію.
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
. Це має сенс?