Conception de la base de données: deux relations 1 à plusieurs vers la même table


20

Je dois modéliser une situation où j'ai une table Chequing_Account (qui contient le budget, le numéro iban et d'autres détails du compte) qui doit être liée à deux tables Person et Corporation différentes qui peuvent toutes deux avoir 0, 1 ou plusieurs comptes de chèques.

En d'autres termes, j'ai deux relations 1 à plusieurs avec le même compte de chèques de table

Je voudrais entendre des solutions à ce problème qui respectent les exigences de normalisation. La plupart des solutions que j'ai entendues sont:

1) trouver une entité commune à laquelle appartiennent à la fois la personne et la société et créer une table de liens entre celle-ci et la table Chequing_Account, ce n'est pas possible dans mon cas et même si c'était le cas, je veux résoudre le problème général et non cette instance spécifique.

2) Créez deux tables de liens PersonToChequingAccount et CorporationToChequingAccount qui relient les deux entités aux comptes de chèques. Cependant, je ne veux pas que deux personnes aient le même compte de chèques, et je ne veux pas qu'une personne physique et une société partagent un compte de chèques! voir cette image

http://i41.tinypic.com/35i6kbk.png

3) Créez deux clés étrangères dans le compte de chèques qui pointent vers la société et la personne physique, mais j'imposerais donc qu'une personne et une société peuvent avoir de nombreux comptes de chèques, mais je devrais m'assurer manuellement que pour chaque ligne de compte de chèques, les deux relations ne pointent pas vers Société et personne physique, car un compte de chèques appartient soit à une société, soit à une personne physique. voir cette image

http://i40.tinypic.com/1rpv9z.png

Existe-t-il une autre solution plus propre à ce problème?


Avez-vous pensé à avoir par exemple un OwnerTypeIDdans le ChecquingAccounttableau, avec 1=Corporationet 2=NaturalPerson? De cette façon, vous n'en avez besoin que d'un OwnerIDdans le ChecquingAccounttableau, que vous pouvez indexer avec le OwnerTypeID.
RoKa

J'ai besoin non seulement de savoir s'il s'agit d'une société ou d'une personne physique mais aussi de connaître l'identifiant respectif, j'ai donc besoin d'un numéro d'identification et pas seulement d'une valeur de 1 ou 2! La solution 3 est ce que j'ai trouvé ici J'ai deux colonnes avec des identifiants pour une société ou une personne physique
dendini

2
Oui, la solution est une option valide. Dans la plupart des SGBD, vous pouvez imposer qu'un seul des deux FK est "actif" avec une contrainte de vérification: CHECK (CorporationID IS NOT NULL AND NaturalPersonID IS NULL OR CorporationID IS NULL AND NaturalPersonID IS NOT NULL)je préfère de loin la solution 1 (mais c'est juste moi). C'est beaucoup plus "propre".
ypercubeᵀᴹ

Oui, je comprends, mais vous pourriez avoir dans le ChecquingAccounttableau un enregistrement de OwnerTypeID=1et OwnerID=123, indiquant qu'il s'agit d'un type Corporation, donc un ID 123dans le Corporationtableau. Le OwnerTypeID vous indique quelle table, et le OwnerID vous indique l'ID dans cette table.
RoKa

1
Comment l'option # 1 est-elle impossible? Le mot «société» signifie essentiellement «une entreprise qui est légalement une personne», après tout. Appelez ça une Customerstable.
Jon de tous les métiers

Réponses:


15

Les bases de données relationnelles ne sont pas conçues pour gérer parfaitement cette situation. Vous devez décider de ce qui est le plus important pour vous et ensuite faire vos compromis. Vous avez plusieurs objectifs:

  • Maintenir la troisième forme normale
  • Maintenir l'intégrité référentielle
  • Maintenez la contrainte que chaque compte appartient à une société ou à une personne physique.
  • Préserver la capacité de récupérer des données simplement et directement

Le problème est que certains de ces objectifs se font concurrence.

Solution de sous-typage
Vous pouvez choisir une solution de sous-typage dans laquelle vous créez un super-type qui intègre à la fois des sociétés et des personnes. Ce super-type aurait probablement une clé composée de la clé naturelle du sous-type plus un attribut de partitionnement (par exemple customer_type). C'est très bien en ce qui concerne la normalisation et cela vous permet d'appliquer l'intégrité référentielle ainsi que la contrainte que les sociétés et les personnes s'excluent mutuellement. Le problème est que cela rend la récupération des données plus difficile, car vous devez toujours créer une branche en fonction du customer_typemoment où vous joignez le compte au titulaire du compte. Cela signifie probablement utiliser UNIONet avoir beaucoup de SQL répétitif dans votre requête.

Solution à deux clés étrangères
Vous pouvez choisir une solution dans laquelle vous conservez deux clés étrangères dans votre table de compte, une pour la société et une pour la personne. Cette solution vous permet également de maintenir l'intégrité référentielle, la normalisation et l'exclusivité mutuelle. Il présente également le même inconvénient de récupération de données que la solution de sous-typage. En fait, cette solution est semblable à la solution de sous-typage, sauf que vous arrivez au problème de branchement de votre logique de jonction "plus tôt".

Néanmoins, de nombreux modélisateurs de données considéreraient cette solution inférieure à la solution de sous-typage en raison de la manière dont la contrainte d'exclusivité mutuelle est appliquée. Dans la solution de sous-typage, vous utilisez des clés pour appliquer l'exclusivité mutuelle. Dans la solution à deux clés étrangères, vous utilisez une CHECKcontrainte. Je connais des gens qui ont un parti pris injustifié contre les contraintes de contrôle. Ces personnes préféreraient la solution qui garde les contraintes dans les clés.

Solution d'attribut de partitionnement "dénormalisé"
Il existe une autre option où vous conservez une seule colonne de clé étrangère dans la table de compte de chèques et utilisez une autre colonne pour vous dire comment interpréter la colonne de clé étrangère (RoKa'sOwnerTypeIDcolonne). Cela élimine essentiellement la table de super-type dans la solution de sous-typage en dénormalisant l'attribut de partitionnement de la table enfant. (Notez qu'il ne s'agit pas strictement de «dénormalisation» selon la définition formelle, car l'attribut de partitionnement fait partie d'une clé primaire.) Cette solution semble assez simple car elle évite d'avoir une table supplémentaire pour faire plus ou moins la même chose et cela réduit le nombre de colonnes de clé étrangère à un. Le problème avec cette solution est qu'elle n'évite pas le branchement de la logique de récupération et de plus, elle ne vous permet pas de maintenir l' intégrité référentielle déclarative . Les bases de données SQL n'ont pas la capacité de gérer une seule colonne de clé étrangère pour l'une des tables parent multiples.

Solution de domaine de clé primaire partagée
Une façon dont les gens traitent parfois ce problème est d'utiliser un seul pool d'ID afin qu'il n'y ait aucune confusion pour un ID donné, qu'il appartienne à un sous-type ou à un autre. Cela fonctionnerait probablement assez naturellement dans un scénario bancaire, car vous n'allez pas émettre le même numéro de compte bancaire à la fois à une société et à une personne physique. Cela a l'avantage d'éviter la nécessité d'un attribut de partitionnement. Vous pouvez le faire avec ou sans table de super-type. L'utilisation d'une table de super-type vous permet d'utiliser des contraintes déclaratives pour appliquer l'unicité. Sinon, cela devrait être appliqué de manière procédurale. Cette solution est normalisée mais elle ne vous permettra pas de maintenir l'intégrité référentielle déclarative à moins de conserver la table de super-type. Il ne fait toujours rien pour éviter une logique de récupération complexe.

Vous pouvez donc voir qu'il n'est pas vraiment possible d'avoir une conception propre qui respecte toutes les règles, tout en gardant la récupération de vos données simple. Vous devez décider où seront vos compromis.


Ma solution n ° 2 à laquelle de vos quatre groupes appartient? La "solution d'attribut de partitionnement dénormalisé" n'est pas tout à fait claire pour moi ..
dendini

@dendini - Votre solution numéro 2 ne correspond à aucune des solutions que j'ai décrites. En effet, cela ne correspond pas à l'exigence d'un compte appartenant à une entité juridique. La façon dont vous avez défini les clés primaires des tables intermédiaires, ce sont des intersections plusieurs-à-plusieurs. Si les clés primaires étaient justes corporation_id et que person_idvous auriez essentiellement la solution de sous-typage, sauf que la table de super-type aurait été divisée en deux et que la clé étrangère aurait été inversée, de sorte que les gens ne pourraient pas détenir plusieurs comptes. Ce genre de défait le but.
Joel Brown

Grande explication. @JoelBrown, quelles sont les implications en termes de performances de la solution "Deux clés étrangères", en termes d'interrogation? De plus, étant donné qu'au lieu de 2, il peut y avoir 6 clés étrangères ou plus: recommanderiez-vous toujours cette approche ou plutôt vous pencher vers une autre?
Amadeo Gallardo

1
@AmadeoGallardo La réponse est "ça dépend". Interroger une clé est toujours assez efficace, car vous pouvez généralement compter sur une analyse d'index au moins, sinon une recherche, et ce sont des opérations rapides. Le problème survient lorsque vous interrogez les deux clés dans la solution à deux clés étrangères . Ici, vous demandez à l'optimiseur de requête d'effectuer une opération soit / ou. Au mieux, cela doublera le coût de la requête, généralement un peu pire, car vous devez interroger une clé, puis l'autre, puis fusionner les résultats.
Joel Brown

@JoelBrown Les futures versions SQL dénormalisées devraient permettre cette approche en permettant la définition d'une clé étrangère composée basée sur deux colonnes RefIDet RefTableRefTableest un identifiant fixe qui identifie la table cible. Il existe de nombreux cas d'utilisation pour ce type de clé et son trop pour maintenir 10 ou plusieurs tables d'association / sous-type pour appliquer l'intégrité. Pour ces cas, je l'ai créé keymoi - même.
djmj
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.