@Bill Karwin décrit trois modèles d'héritage dans son livre SQL Antipatterns , lorsqu'il propose des solutions à l' antipattern SQL Entity-Attribute-Value . Voici un bref aperçu:
Héritage de table unique (alias héritage de table par hiérarchie):
L'utilisation d'une seule table comme dans votre première option est probablement la conception la plus simple. Comme vous l'avez mentionné, de nombreux attributs spécifiques au sous-type devront recevoir une NULL
valeur sur les lignes où ces attributs ne s'appliquent pas. Avec ce modèle, vous auriez une table de stratégies, qui ressemblerait à ceci:
+------+---------------------+----------+----------------+------------------+
| 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 -----/
Garder la conception simple est un plus, mais les principaux problèmes de cette approche sont les suivants:
En ce qui concerne l'ajout de nouveaux sous-types, vous devez modifier le tableau pour tenir compte des attributs qui décrivent ces nouveaux objets. Cela peut rapidement devenir problématique lorsque vous disposez de nombreux sous-types ou si vous prévoyez d'ajouter régulièrement des sous-types.
La base de données ne pourra pas appliquer les attributs qui s'appliquent et ceux qui ne le sont pas, car il n'y a pas de métadonnées pour définir quels attributs appartiennent à quels sous-types.
Vous ne pouvez pas non plus appliquer NOT NULL
les attributs d'un sous-type qui devraient être obligatoires. Vous devrez gérer cela dans votre application, ce qui n'est généralement pas idéal.
Héritage de table en béton:
Une autre approche pour lutter contre l'héritage consiste à créer une nouvelle table pour chaque sous-type, en répétant tous les attributs communs de chaque table. Par exemple:
--// 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 |
+------+---------------------+------------------+
Cette conception résoudra essentiellement les problèmes identifiés pour la méthode à table unique:
Les attributs obligatoires peuvent désormais être appliqués avec NOT NULL
.
L'ajout d'un nouveau sous-type nécessite l'ajout d'une nouvelle table au lieu d'ajouter des colonnes à une existante.
Il n'y a également aucun risque qu'un attribut inapproprié soit défini pour un sous-type particulier, tel que le vehicle_reg_no
champ d'une stratégie de propriété.
Il n'est pas nécessaire pour l' type
attribut comme dans la méthode de table unique. Le type est désormais défini par les métadonnées: le nom de la table.
Cependant, ce modèle présente également quelques inconvénients:
Les attributs communs sont mélangés avec les attributs spécifiques au sous-type, et il n'existe aucun moyen facile de les identifier. La base de données ne le saura pas non plus.
Lors de la définition des tables, vous devrez répéter les attributs communs pour chaque table de sous-type. Ce n'est certainement pas SEC .
La recherche de toutes les politiques, quel que soit le sous-type, devient difficile et nécessiterait un tas de UNION
s.
Voici comment vous devez interroger toutes les stratégies quel que soit le type:
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;
Notez que l'ajout de nouveaux sous-types nécessiterait la modification de la requête ci-dessus avec un supplément UNION ALL
pour chaque sous-type. Cela peut facilement entraîner des bogues dans votre application si cette opération est oubliée.
Héritage de table de classe (alias héritage de table par type):
C'est la solution que @David mentionne dans l'autre réponse . Vous créez une table unique pour votre classe de base, qui comprend tous les attributs communs. Ensuite, vous devez créer des tables spécifiques pour chaque sous-type, dont la clé primaire sert également de clé étrangère à la table de base. Exemple:
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)
);
Cette solution résout les problèmes identifiés dans les deux autres conceptions:
Les attributs obligatoires peuvent être appliqués avec NOT NULL
.
L'ajout d'un nouveau sous-type nécessite l'ajout d'une nouvelle table au lieu d'ajouter des colonnes à une existante.
Aucun risque qu'un attribut inapproprié soit défini pour un sous-type particulier.
Pas besoin de l' type
attribut.
Maintenant, les attributs communs ne sont plus mélangés avec les attributs spécifiques au sous-type.
Nous pouvons enfin rester SECS. Il n'est pas nécessaire de répéter les attributs communs pour chaque table de sous-type lors de la création des tables.
La gestion d'une incrémentation automatique id
pour les stratégies devient plus facile, car elle peut être gérée par la table de base, au lieu que chaque table de sous-type les génère indépendamment.
La recherche de toutes les politiques, quel que soit le sous-type, devient désormais très simple: pas UNION
besoin de - juste a SELECT * FROM policies
.
Je considère l'approche de la table de classe comme la plus appropriée dans la plupart des situations.
Les noms de ces trois modèles proviennent du livre Patterns of Enterprise Application Architecture de Martin Fowler .