Je suis en train de concevoir une base de données pour notre équipe de vente à utiliser comme un outil de soumission rapide. J'aimerais avoir des commentaires sur un aspect particulier de la conception.
Un devis est essentiellement constitué en sélectionnant une liste d '«assemblages» prédéfinis, chacun avec un prix convenu. Une vue simplifiée du formulaire principal ressemble à ceci:
+------------ --- ---+
| Assembly options |
+------------+------------+----------+------------+---+---+---+ --- +--+
| assembly ▼ | unit cost | quantity | total cost | 1 | 2 | 3 | |50|
+------------+------------+----------+------------+---+---+---+ --- +--+
| VSD55 | £10'000 | 2 | £25'500 | 1 | 1 | | | |
| RDOL2.2 | £2'000 | 1 | £1'500 | | 1 | | | |
| DOL5.0 | £1'000 | 1 | £1'200 | | | 1 | | |
+------------+------------+----------+------------+---+---+---+ --- +--+
L'utilisateur sélectionne un assemblage prédéfini, saisit la quantité et sélectionne les «options» requises. Chaque assemblage a potentiellement jusqu'à 50 options disponibles. Une option est également un assemblage prédéfini (sous-assemblage) avec son propre prix. Le «coût total» pour chaque ligne est calculé comme (coût d'assemblage principal * quantité) + coût de toutes les options.
Lorsque l'utilisateur déplace son curseur dans une case d'option, le nom et le prix de cette option lui sont communiqués.
Maintenant, c'est là que ça se complique. Chaque assemblage possède sa propre liste d'options disponibles. c'est-à-dire que l'option 1 pour un «VSD55» représente un sous-ensemble différent de l'option 1 pour un DOL5.0.
En ce qui concerne les assemblages, voici les tableaux simplifiés que j'utilise:
+-----------------+ +------------------------+ +-----------------------------+
| assembly | | assembly_option | | assembly_option_link |
+-----------------+ +------------------------+ +-----------------------------+
| assembly_id (PK)| | assembly_option_id (PK)| | assembly_option_link_id (PK)|
| assembly_name | | assembly_option_name | | assembly_id (FK) |
| unit_cost | | option_number | | assembly_option_id (FK) |
+-----------------+ | unit_cost | +-----------------------------+
+------------------------+
Le tableau 'assembly_option_link' définit essentiellement les options disponibles pour chaque assembly.
Maintenant, pour les tableaux «devis»:
+-----------------+ +------------------------+
| quote | | quote_assembly |
+-----------------+ +------------------------+
| quote_id (PK) | | quote_assembly_id (PK) |
| quote_name | | assembly_id (FK) |
+-----------------+ | quantity |
+------------------------+
Maintenant, la partie délicate est de savoir comment stocker les options sélectionnées. Dois-je développer la table 'quote_assembly' avec tous les 50 champs d'options même si cela enfreint les règles de normalisation. Un assemblage ne sera jamais sélectionné avec les 50 options, ce qui semble également très inefficace. Sur le plan positif, cette solution permet au formulaire de saisie utilisateur de mapper directement sur le tableau, ce qui facilite le codage.
La solution «normalisée», je pense, serait de créer un autre tableau comme celui-ci:
+------------------------------+
| quote_assembly_option |
+------------------------------+
| quote_assembly_option_id (PK)|
| quote_assembly_id (FK) |
| assembly_option_id (FK) |
| quantity |
+------------------------------+
Cette solution signifie que seules les options sélectionnées sont stockées. De plus, plutôt que de stocker l'option_number, je peux stocker le 'assembly_option_id' réel. Cela rend ensuite le calcul du coût total du devis plus simple car je n'ai pas besoin de convertir entre 'option_number' et 'assembly_option_id' pour rechercher le coût de l'option d'assemblage. L'inconvénient majeur de cette solution est qu'elle ne convient pas au formulaire de saisie utilisateur. Je pense que je devrai appliquer un codage sophistiqué pour interfacer le formulaire avec les tables.
Quelqu'un peut-il offrir des conseils de conception ici s'il vous plaît? J'espère que je me suis bien expliqué.
PLUS D'INFO
Le est également un rapport de devis détaillé qui développe toutes les options sélectionnées en tant qu'éléments de ligne distincts sous l'assemblage principal. Par exemple:
+---------------------------------+------------+----------+------------+
| assembly | unit cost | quantity | total cost |
+---------------------------------+------------+----------+------------+
| VSD55 | £10'000 | 2 | £20'000 |
| - Seal leak protection | £ 5'000 | 1 | £ 5'000 | <-option 1
| - Motor over temp protection | £ 500 | 1 | £ 500 | <-option 2
+---------------------------------+------------+----------+------------+
| | | | £25'500 |
+---------------------------------+------------+----------+------------+
La dernière option que vous donnez est la façon dont j'irais avec. Et renvoyez deux tables groupées, une pour la "ligne principale" et une pour les lignes "existe-t-il" collectées pour les 50 colonnes. En supposant que vous pouvez mapper l'option à son ID de colonne approprié assez facilement (il semble que vous le puissiez sans trop de difficultés).
Ce serait assez facile pour l'itération, en supposant un langage comme C #, où vous avez LINQ disponible, etc. Celles-ci sont assez faciles à faire, même si elles impliquent un peu de boucle (c'est du code UI, cela doit être fait à un moment donné) ). Ou vous pouvez faire un pivot dans la base de données avant de revenir ... ce serait plus rapide. Mais cela maintiendra toujours la complexité.
Mais votre conception me semble saine.
la source
L'ajout de votre table supplémentaire me semble également assez solide.
Face à un problème similaire de ma part, j'ai exploré le stockage d'un arbre dans la table order_lines. Dans le cas où vous envisagez quelque chose de similaire, j'avais:
un
parent_id
champ supplémentaire pourorder_lines
, et une clé étrangère de sorte que(parent_id, product_id)
ferait référence(order_line_id, product_id)
Une contrainte de vérification pour faire avoir une option impliquerait un parent (dans mon cas
check((option_id is not null) = (parent_id is not null))
).En d'autres termes, je laisse l'interface utilisateur avoir un mot sur la façon dont les choses doivent être stockées:
Du point de vue du codage de l'interface utilisateur, cela semblait juste. Mais il s'est rapidement senti mal du point de vue des règles commerciales, en ce sens qu'il a introduit une variété de problèmes en cours de route. (J'ai dû gérer toutes sortes de cas spéciaux dans les déclencheurs.)
Donc pas recommandé ... Dans la mesure où j'ai connu des cas similaires, votre approche actuelle sera moins sujette aux problèmes sur la route.
la source