Mi imbatto in una situazione nel database abbastanza frequentemente in cui una determinata tabella può essere utilizzata da una delle diverse tabelle principali. Ho visto due soluzioni al problema, ma nessuna delle due è soddisfacente. Sono curioso di sapere quali altri schemi hai visto là fuori? C'è un modo migliore per farlo?
Un esempio contrastato
Diciamo che il mio sistema ha Alerts
. Gli avvisi possono essere ricevuti per una varietà di oggetti: clienti, notizie e prodotti. Un determinato avviso può essere per un solo elemento. Per qualsiasi motivo, clienti, articoli e prodotti si spostano rapidamente (o localizzati), pertanto il testo / i dati necessari non possono essere inseriti negli avvisi al momento della creazione di un avviso. Data questa configurazione, ho visto due soluzioni.
Nota: sotto DDL è per SQL Server ma la mia domanda dovrebbe essere applicabile a qualsiasi DBMS.
Soluzione 1 - Più tasti Nullable
In questa soluzione la tabella che collega a una delle tante tabelle ha più colonne FK (per brevità il DDL sottostante non mostra la creazione di FK). IL BUONO - In questa soluzione è bello avere chiavi esterne. La null-optinalità degli FK rende questo comodo e relativamente facile aggiungere dati precisi. THE BAD Querying non è eccezionale perché richiede N LEFT JOINS o N UNION per ottenere i dati associati. In SQL Server, in particolare i JOIN LEFT precludono la creazione di una vista indicizzata.
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)
)
Soluzione 2: un FK in ciascuna tabella padre
In questa soluzione ogni tabella "padre" ha un FK nella tabella avvisi. Semplifica il recupero degli avvisi associati a un genitore. Sul lato negativo, non esiste una vera catena dall'Allerta a chi fa riferimento. Inoltre, il modello di dati consente avvisi orfani, in cui un avviso non è associato a un prodotto, a una notizia o a un cliente. Ancora una volta, più LEFT JOIN per capire l'associazione.
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)
)
È solo la vita in un database di relazioni? Ci sono soluzioni alternative che hai trovato più soddisfacenti?
Alertable
. Ha senso?