Des désirs contradictoires dans la conception de base de données, avec des champs de deux fonctions similaires

StackOverflow https://stackoverflow.com/questions/112780

Question

D'accord, je crée dès maintenant un tableau pour les "éléments de boîte".

Désormais, un élément de boîte, en fonction de son utilisation / du statut de l’article, peut être associé à un "Expédition". une boîte ou un " retours " boîte.

Un élément de boîte peut être défectueux: dans ce cas, un indicateur sera placé dans la ligne de l'élément de boîte (IsDefective), et l'élément de boîte sera placé dans un "Retours". boîte (avec les autres articles à retourner à ce fournisseur). Sinon, l’article de la boîte sera éventuellement placé dans un " Expédition " boîte (avec d'autres articles à expédier). (Notez que les boîtes d’expédition et de retour ont leurs propres tables: il n’existe pas une table commune à toutes les boîtes ... mais je devrais peut-être envisager de le faire si possible comme troisième possibilité?)

Peut-être que je ne réfléchis pas clairement aujourd'hui, mais j'ai commencé à me demander ce qui devrait être fait dans cette situation.

Mon instinct me dit que je devrais avoir un champ séparé pour chaque relation possible, même si une seule des relations peut se produire à un moment donné, ce qui donnerait le schéma suivant pour les éléments Box:

BoxItemID La description Est défectueux ShippingBoxID ReturnBoxID etc ...

Cela clarifierait les relations, mais cela semble inutile (car une seule des relations sera utilisée à tout moment). J'ai alors pensé que je ne pouvais avoir qu'un seul champ pour le BoxID et déterminer le BoxID auquel il fait référence (un ID de boîte d'expédition ou de retour) en fonction du champ IsDefective:

BoxItemID La description Est défectueux BoxID etc ...

Cela semble moins gaspiller, mais ne reste pas assis avec moi. La relation n’est pas évidente.

Donc, je vous le présente, gourous de la base de données de Stackoverflow. Que feriez-vous dans cette situation?

EDIT: Merci à tous pour votre contribution! Cela m'a donné beaucoup de choses à penser. D'une part, je vais utiliser un ORM la prochaine fois que je démarre un projet comme celui-ci. =) Pour deux, puisque je ne suis pas en ce moment, je vais mordre les quatre octets et utiliser deux champs.

Merci encore à tous!

Était-ce utile?

La solution

Je suis avec venin psychotique et mattlant.

Choisir la route polymorphe (savoir à quelle table pointe votre clé étrangère en fonction du contenu d'un autre champ) va être une tâche ardue. Il peut être difficile de coder les contraintes pour cela (je ne suis pas sûr que la plupart des bases de données prendraient cela en charge en natif, je pense qu'il faudrait utiliser un déclencheur).

Les objets se déplacent-ils jamais d'une table à l'autre? S'en tenir à deux tables avec des définitions identiques où l'une est pour les retours et l'autre pour l'expédition peut être la voie la plus facile. Si vous voulez vous en tenir à la définition que vous avez proposée en premier (avec les deux champs distincts), cela est parfaitement raisonnable.

"L’optimisation prématurée est la racine de tous les maux" et tout ça. Bien que cela semble inutile, souvenez-vous de ce que vous stockez. Comme ce sont des identifiants, ce ne sont probablement que des entiers, peut-être 4 octets. Le gaspillage de quatre octets par enregistrement n’est fondamentalement rien. En fait, en raison du remplissage pour mettre des choses même sur des adresses ou autres choses similaires, il peut être "gratuit". pour mettre ce champ supplémentaire là-bas. Tout dépend de la conception de la base de données.

À moins que vous n'ayez une très bonne raison de choisir la voie polymorphe (comme sur un système embarqué avec peu de mémoire ou que vous devez répliquer sur un lien très lent à 9 600 bps), cela ne vaudra probablement pas la peine que vous pouvez vous en donner finir avec. Devoir écrire tous ces cas spéciaux dans vos requêtes peut devenir ennuyeux.

Exemple rapide: faire une jointure entre deux tables où si vous voulez vous joindre est basé sur si l'indicateur isDefective est défini, cela va être un problème. Etre capable de n'utiliser que l'une des deux colonnes seule est probablement assez fastidieux pour vous, au moins pour moi. Vous enregistrez.

Autres conseils

J'envisagerais de créer une seule table pour les boîtes et le type de boîte sera une colonne de la table des boîtes. Cela simplifierait les relations et faciliterait l'interrogation du type de boîte. Ainsi, l'élément de boîte n'a qu'une clé étrangère pour la boîteId.

Je voudrais utiliser ce que Hibernate appelle Tableau- par-classe , afin que ma base de données se termine avec 3 tables pour les zones: Box , ShippingBox et ReturnBox . Le FK dans BoxItem pointe vers Box .

Vous parlez de relations polymorphes. Un identifiant unique pouvant référencer plusieurs autres tables. Plusieurs frameworks prennent en charge cela, cependant, il est (potentiellement) mauvais pour l’intégrité de la base de données (cela pourrait être une toute autre discussion de savoir si votre base de données ou votre application doit maintenir l’intégrité référentielle).

Qu'en est-il?

BoxItem:
BoxItemID, Description, IsDefective

Box:
BoxID, Description

BoxItemMap:
BoxID, BoxItemID, BoxItemType

Ensuite, vous pouvez faire de BoxItemType une énumération ou un entier dans lequel vous définissez les constantes dans votre application en tant que " Return " ou "Expédition" comme type de boîte.

D’accord sur la discussion polymorphe ci-dessus, bien qu’elle puisse potentiellement être mal utilisée, elle reste une solution viable.

En gros, vous avez une table de base appelée box. Ensuite, vous avez deux autres tables, boîte d'expédition et boîte de retour. Ces deux ajoutent tous les champs supplémentaires qui leur sont spéciaux. ils sont liés à box avec une table de base fk.Boz 1: 1 qui contient les champs communs de tous les types de box.

Vous associez BoxItem à la table box. Vous obtenez le type de boîte approprié en effectuant une requête qui joint la boîte enfant à la boîte racine en fonction de la clé. L’enregistrement qui figure à la fois dans la boîte de base et dans la boîte d’enfant est de ce type.

Vous devez juste faire attention, comme mentionné lorsque vous créez un type de boîte que cela est fait correctement. Mais c'est à quoi servent les tests. Le code pour les ajouter n'a besoin d'être écrit qu'une seule fois. Ou utilisez un ORM.

Presque tous les ORM soutiennent cette stratégie.

Je n'utiliserais qu'une seule table BoxItems avec IsDefective, ShippingBoxID, les champs liés à la boîte d'expédition, ReturnBoxID et les champs associés à la boîte de retour. Certains champs auront toujours la valeur NULL pour chaque enregistrement.

C’est une conception très simple et qui va de soi que le prochain développeur ne risque pas d’être confondue. En théorie, cette conception est inefficace en raison des champs vides garantis pour chaque ligne. En pratique, les bases de données ont de toute façon tendance à avoir une taille de stockage minimale pour chaque ligne. Ainsi, (sauf si le nombre de champs est énorme), cette conception est néanmoins aussi efficace que possible et beaucoup plus facile à coder.

J'irais probablement avec:

BoxTable:
box_id, box_descrip, box_status_id ...
     1, Lovely Box, 1
     2, Borked box, 2
     3, Ugly Box, 3
     4, Flammable Box, 4

       BoxStatus:
       box_status_id, box_status_name, box_type_id, ....
                   1,Shippable, 1
                   2,Return, 2
                   3,Ugly, 2
                   4,Dangerous,3

                BoxType:
                box_type_id, box_type_name, ...
                          1, Shipping box, ...
                          2, Return box, ....
                          3, Hazmat box, ...

De cette manière, l’état de la boîte définit le type de boîte et vous permet de modifier ultérieurement plusieurs niveaux d’état ou types de boîte.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top