@Bill Karwin descrive tre modelli di ereditarietà nel suo libro SQL Antipatterns , quando propone soluzioni per l' antipattern SQL Entity-Attribute-Value . Questa è una breve panoramica:
Ereditarietà a tabella singola (aka Table Per Hierarchy Inheritance):
Usare una singola tabella come nella tua prima opzione è probabilmente il design più semplice. Come accennato, a molti attributi specifici del sottotipo dovrà essere assegnato un NULL
valore nelle righe in cui questi attributi non si applicano. Con questo modello, avresti una tabella delle politiche, che sarebbe simile a questa:
+------+---------------------+----------+----------------+------------------+
| id | date_issued | type | vehicle_reg_no | property_address |
+------+---------------------+----------+----------------+------------------+
| 1 | 2010-08-20 12:00:00 | MOTOR | 01-A-04004 | NULL |
| 2 | 2010-08-20 13:00:00 | MOTOR | 02-B-01010 | NULL |
| 3 | 2010-08-20 14:00:00 | PROPERTY | NULL | Oxford Street |
| 4 | 2010-08-20 15:00:00 | MOTOR | 03-C-02020 | NULL |
+------+---------------------+----------+----------------+------------------+
\------ COMMON FIELDS -------/ \----- SUBTYPE SPECIFIC FIELDS -----/
Mantenere il design semplice è un vantaggio, ma i problemi principali con questo approccio sono i seguenti:
Quando si tratta di aggiungere nuovi sottotipi, è necessario modificare la tabella per adattarsi agli attributi che descrivono questi nuovi oggetti. Questo può diventare rapidamente problematico quando si hanno molti sottotipi o se si prevede di aggiungere regolarmente sottotipi.
Il database non sarà in grado di imporre quali attributi si applicano e quali no, poiché non esistono metadati per definire quali attributi appartengono a quali sottotipi.
Inoltre, non è possibile applicare gli NOT NULL
attributi di un sottotipo che dovrebbero essere obbligatori. Dovresti gestirlo nella tua applicazione, che in generale non è l'ideale.
Ereditarietà concreta della tabella:
Un altro approccio per affrontare l'ereditarietà è quello di creare una nuova tabella per ciascun sottotipo, ripetendo tutti gli attributi comuni in ciascuna tabella. Per esempio:
--// Table: policies_motor
+------+---------------------+----------------+
| id | date_issued | vehicle_reg_no |
+------+---------------------+----------------+
| 1 | 2010-08-20 12:00:00 | 01-A-04004 |
| 2 | 2010-08-20 13:00:00 | 02-B-01010 |
| 3 | 2010-08-20 15:00:00 | 03-C-02020 |
+------+---------------------+----------------+
--// Table: policies_property
+------+---------------------+------------------+
| id | date_issued | property_address |
+------+---------------------+------------------+
| 1 | 2010-08-20 14:00:00 | Oxford Street |
+------+---------------------+------------------+
Questo progetto risolverà sostanzialmente i problemi identificati per il metodo a tabella singola:
Ora è possibile applicare attributi obbligatori NOT NULL
.
L'aggiunta di un nuovo sottotipo richiede l'aggiunta di una nuova tabella anziché l'aggiunta di colonne a una esistente.
Inoltre, non esiste alcun rischio che venga impostato un attributo inappropriato per un particolare sottotipo, ad esempio il vehicle_reg_no
campo per una politica delle proprietà.
Non è necessario per l' type
attributo come nel metodo a tabella singola. Il tipo è ora definito dai metadati: il nome della tabella.
Tuttavia, questo modello presenta anche alcuni svantaggi:
Gli attributi comuni sono mescolati con gli attributi specifici del sottotipo e non esiste un modo semplice per identificarli. Il database non lo saprà neanche.
Quando si definiscono le tabelle, è necessario ripetere gli attributi comuni per ciascuna tabella dei sottotipi. Non è assolutamente ASCIUTTO .
La ricerca di tutte le politiche indipendentemente dal sottotipo diventa difficile e richiederebbe un sacco di UNION
s.
Ecco come dovresti interrogare tutti i criteri indipendentemente dal tipo:
SELECT date_issued, other_common_fields, 'MOTOR' AS type
FROM policies_motor
UNION ALL
SELECT date_issued, other_common_fields, 'PROPERTY' AS type
FROM policies_property;
Nota come l'aggiunta di nuovi sottotipi richiederebbe la modifica della query sopra con un ulteriore UNION ALL
per ciascun sottotipo. Questo può facilmente portare a bug nella tua applicazione se questa operazione viene dimenticata.
Ereditarietà delle tabelle di classe (nota anche come ereditarietà delle tabelle):
Questa è la soluzione menzionata da @David nell'altra risposta . Si crea una singola tabella per la classe di base, che include tutti gli attributi comuni. Quindi creare tabelle specifiche per ciascun sottotipo, la cui chiave primaria funge anche da chiave esterna per la tabella di base. Esempio:
CREATE TABLE policies (
policy_id int,
date_issued datetime,
-- // other common attributes ...
);
CREATE TABLE policy_motor (
policy_id int,
vehicle_reg_no varchar(20),
-- // other attributes specific to motor insurance ...
FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);
CREATE TABLE policy_property (
policy_id int,
property_address varchar(20),
-- // other attributes specific to property insurance ...
FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);
Questa soluzione risolve i problemi identificati negli altri due progetti:
È possibile applicare attributi obbligatori NOT NULL
.
L'aggiunta di un nuovo sottotipo richiede l'aggiunta di una nuova tabella anziché l'aggiunta di colonne a una esistente.
Nessun rischio che venga impostato un attributo inappropriato per un particolare sottotipo.
Non è necessario per l' type
attributo.
Ora gli attributi comuni non vengono più mescolati con gli attributi specifici del sottotipo.
Finalmente possiamo restare ASCIUTTI. Non è necessario ripetere gli attributi comuni per ciascuna tabella dei sottotipi durante la creazione delle tabelle.
La gestione di un incremento automatico id
per i criteri diventa più semplice, poiché può essere gestita dalla tabella di base anziché da ciascuna tabella dei sottotipi generandoli in modo indipendente.
La ricerca di tutte le politiche indipendentemente dal sottotipo ora diventa molto semplice: non UNION
è necessario, solo a SELECT * FROM policies
.
Considero l'approccio del tavolo di classe come il più adatto nella maggior parte delle situazioni.
I nomi di questi tre modelli derivano dal libro Patterns of Enterprise Application Architecture di Martin Fowler .