Consejo de diseño de bases de datos

8

Estoy diseñando una base de datos para que nuestro equipo de ventas la use como una herramienta rápida para cotizar trabajos. Me gustaría recibir comentarios sobre un aspecto particular del diseño.

Básicamente, se crea una cotización seleccionando una lista de 'ensambles' predefinidos, cada uno con un precio acordado. Una vista simplificada del formulario principal se ve así:

                                                  +------------ --- ---+
                                                  | 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 |     |  | 
+------------+------------+----------+------------+---+---+---+ --- +--+

El usuario selecciona un ensamblaje predefinido, ingresa la cantidad y selecciona cualquier 'opción' requerida. Cada conjunto tiene potencialmente hasta 50 opciones disponibles. Una opción también es un ensamblaje predefinido (subensamblaje) con su propio precio. El 'costo total' para cada línea se calcula como (costo de ensamblaje principal * cantidad) + costo de cualquier opción.

Cuando el usuario mueve su cursor a un cuadro de opción, el nombre y el precio de esa opción se dan a conocer.

Ahora aquí es donde se complica. Cada conjunto tiene su propia lista de opciones disponibles. es decir, la opción 1 para un 'VSD55' representa un subconjunto diferente que la opción 1 para un DOL5.0.

En cuanto a los ensamblajes, aquí están las tablas simplificadas que estoy usando:

+-----------------+    +------------------------+    +-----------------------------+
| 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              |    +-----------------------------+
                       +------------------------+

La tabla 'assembly_option_link' básicamente define qué opciones están disponibles para cada ensamblaje.

Ahora para las tablas de 'cotización':

 +-----------------+    +------------------------+    
 | quote           |    | quote_assembly         |    
 +-----------------+    +------------------------+    
 | quote_id (PK)   |    | quote_assembly_id (PK) |
 | quote_name      |    | assembly_id (FK)       |
 +-----------------+    | quantity               |
                        +------------------------+    

Ahora la parte difícil es cómo almacenar las opciones seleccionadas. ¿Debo expandir la tabla 'quote_assembly' con los 50 campos de opciones aunque esto rompa las reglas de normalización? Nunca se seleccionará un ensamblaje con las 50 opciones, por lo que esto también parece muy ineficiente. En el lado positivo, esta solución permite que el formulario de entrada del usuario se asigne directamente a la tabla, lo que facilita la codificación.

La solución 'normalizada' creo que sería crear otra tabla como esta:

+------------------------------+
| quote_assembly_option        |
+------------------------------+
| quote_assembly_option_id (PK)|
| quote_assembly_id (FK)       |
| assembly_option_id (FK)      |
| quantity                     |
+------------------------------+

Esta solución significa que solo se almacenan las opciones seleccionadas. Además, en lugar de almacenar el número_opción, puedo almacenar el 'ensamblado_opción_id' real. Esto hace que el cálculo del costo total de la cotización sea más simple, ya que no necesito convertir entre 'option_number' y 'assembly_option_id' para buscar el costo de la opción de ensamblaje. Sin embargo, el principal inconveniente de esta solución es que no se adapta bien al formulario de entrada del usuario. Creo que necesitaré aplicar una codificación elegante para interconectar el formulario con las tablas.

¿Alguien puede ofrecer algún consejo de diseño aquí, por favor? Espero haberme explicado lo suficientemente bien.

MÁS INFORMACIÓN
También es un informe de presupuesto detallado que amplía las opciones seleccionadas como líneas de pedido separadas en el ensamblaje principal. Por ejemplo:

+---------------------------------+------------+----------+------------+
| 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  |
+---------------------------------+------------+----------+------------+
David
fuente

Respuestas:

3
                                                  +------------ --- ---+
                                                  | Assembly options   |
+------------+------------+----------+------------+---+---+---+ --- +--+
| assembly  | unit cost  | quantity | total cost | 1 | 2 | 3 |     |50|
+------------+------------+----------+------------+---+---+---+ --- +--+
| VSD55      | £10'000    | 2        | £20'000    | 1 | 1 |   |     |  | 

Si alguien me entregara esa cita, mi primera pregunta sería "¿Cuál es la opción 1 para el VSD55?" La respuesta sería "No sé". Esa información no está en la cita. En el caso improbable de que esa persona respondiera una segunda pregunta, esa pregunta sería "¿Cuánto cuesta?" Nuevamente, la respuesta sería "No sé". Inmediatamente se produciría un silencio muy perturbador, durante el cual la persona que me entregó la cita imaginaría cuánto mejor se sentiría ser atropellado por un tren.

Las opciones deben ser líneas de pedido en la cotización, junto con su precio unitario, cantidad y precio total. Las opciones deben ser nombradas, no numeradas. También deberían aparecer directamente debajo de su asamblea de padres, no dispersos por todo el infierno y la mitad de Georgia.

Si quieres una oportunidad por mi dinero, será mejor que aclares lo que se supone que debo obtener por mi dinero.

No hay nada (mucho) incorrecto con 50 casillas de verificación en un formulario de interfaz de usuario. Eso hace que sea fácil elegir opciones. Pero el código de la interfaz de usuario debe leer las casillas de verificación e insertar la información correcta en las tablas normalizadas.

Mike Sherrill 'Retiro del gato'
fuente
Parece que está ofreciendo consejos sobre los procesos de negocios, que no son una opción, que David está tratando de resumir de la mejor manera que conoce para el proyecto que le han asignado. ~ Ahora, estoy de acuerdo en que un dba debería influir en el diseño donde pueda, pero a veces eso no se puede evitar. También tenga en cuenta que esta es una herramienta interna (vea la primera línea)
jcolebrand
1
Comentarios bastante justos, me hicieron reír! Por supuesto, tenemos un informe de cotizaciones que hace exactamente lo que usted sugiere. Desde entonces he agregado este detalle a la pregunta original para evitar más discusiones fuera del tema;)
David
3

La última opción que das es la forma en que yo iría con ella. Y devuelva dos tablas agrupadas, una para la "fila principal" y otra para las filas recopiladas "existe" para las 50 columnas. Suponiendo que puede asignar la opción a su ID de columna adecuada con bastante facilidad (parece que puede hacerlo sin demasiado tiempo difícil).

Eso sería bastante fácil para la iteración, suponiendo un lenguaje como C #, donde tiene LINQ disponible, etc. Esos son lo suficientemente fáciles de hacer, incluso si implican un poco de bucle (es el código de la interfaz de usuario, debe hacerse en algún momento ) O podría hacer un pivote en la base de datos antes de regresar ... eso sería más rápido. Pero aún mantendrá la complejidad.

Pero tu diseño me suena bien.

jcolebrand
fuente
0

Agregar su mesa extra también me parece bastante acertado.

Al tratar con un problema similar de mi parte, exploré el almacenamiento de un árbol en la tabla order_lines. En caso de que haya considerado algo similar, tuve:

  • un parent_idcampo adicional para order_linesy una clave foránea para que haga (parent_id, product_id)referencia(order_line_id, product_id)

  • Una restricción de verificación para tener una opción implicaría un padre (en mi caso check((option_id is not null) = (parent_id is not null))).

En otras palabras, dejo que la interfaz de usuario tenga una palabra sobre cómo deben almacenarse las cosas:

+---------------------------------+------------+----------+------------+
| assembly                        | unit cost  | quantity | total cost |
+---------------------------------+------------+----------+------------+
| VSD55                           | £10'000    | 2        |   £20'000  |
|   - Seal leak protection        | £ 5'000    | 1        |   £ 5'000  |
|   - Motor over temp protection  | £   500    | 1        |   £   500  |
+---------------------------------+------------+----------+------------+

Desde el punto de vista de la codificación UI, parecía correcto. Pero rápidamente se sintió mal desde el punto de vista de la regla de negocios, ya que introdujo una variedad de problemas en el futuro. (Tuve que lidiar con todo tipo de casos especiales en los desencadenantes).

Por lo tanto, no se recomienda ... En la medida en que he experimentado casos similares, su enfoque actual será menos propenso a problemas en el futuro.

Denis de Bernardy
fuente