La mejor manera de almacenar unidades en la base de datos

21

Heredé una gran base de datos (SQLServer) con cientos de columnas que representan cantidades de una cosa u otra. Las unidades para estos valores (por ejemplo, "galones", "pulgadas", etc.) se almacenan en el campo Descripción MS_ de Propiedades extendidas. Me pregunto si hay una mejor manera de almacenar esta información. Supongo que está bien para fines de documentación, pero sería difícil hacer cálculos sólidos de conversión de unidades basados ​​en estos datos. En este momento no estoy preparado para hacer un cambio invasivo, pero si tengo la oportunidad de hacerlo, ¿cuál es la mejor práctica recomendada a este respecto? Las opciones, fuera de mi alcance, pueden incluir:

  • Cambie el nombre de la columna a las unidades incluidas (por ejemplo, "TotalVolumeInGallons". Esto haría que la información esté un poco más disponible, pero aún me parece débil).
  • Agregue una columna de "Unidades" separada para corresponder a cada columna de "Cantidad" (esta columna podría ser nvarchar O podría ser una clave foránea para una tabla de Unidades separada que podría facilitar el cálculo de las conversiones de unidades. Por otro lado, agregar muchas columnas podrían duplicar bastante el tamaño de mi base de datos, con datos terriblemente redundantes).
  • Cree un nuevo campo en Propiedades extendidas dedicado específicamente para unidades. (Desafortunadamente, no creo que esto pueda ser una clave foránea para una tabla de Unidades).
  • ¿Hay otra idea que estoy pasando por alto?

ACTUALIZACIÓN: Después de leer la respuesta de @Todd Everett, se me ocurrió una posible solución, así que voy a seguir adelante y responder mi propia pregunta. (Vea abajo)

kmote
fuente
La mejor práctica es tener un único sistema de medición utilizado universal y consistentemente en toda la aplicación. SI sería el sistema de elección. Los valores en otros sistemas se convertirán durante la carga o en la capa de presentación, donde cada usuario puede elegir su conjunto preferido.
Michael Green

Respuestas:

12

Como mencionas cientos de columnas, consideraría un diseño EAV . Mientras que Joe Celko advierte contra esto , creo que puede ser aplicable en su caso de uso. Parece que todas sus "cantidades" son números, por lo que evitaría los problemas de conversión que describe Joe y la necesidad de convertir cada "valor" en una cadena. Funcionará aún mejor si todas las cantidades son números enteros, pero también puede funcionar si algunas son decimales. Dadas las Unidades de medida, podría ir un paso más allá e implementar un modelo de estilo de "modelo de datos universal" basado en este artículo de David Hay y también descrito en su libro Patrones de modelo de datos: Convenciones de pensamiento . Este modelo tiene la ventaja adicional de configurar qué "cantidades" se aplican a qué "cosas" si lo necesita. Un paso adicional que se muestra en el libro de la página 162 es una tabla de conversión de unidades de medida que puede utilizar para convertir entre las diferentes unidades de medida. Aquí hay un ejemplo:

UOM Conversion              

UOM From    UOM To        Cal Step  Operator Factor Constant
Kilograms   Pounds        1         *        2.2
Celsius     Fahrenheit    1         *        1.8
Celsius     Fahrenheit    2         +               32

Esto dice que para convertir de Kg a Lb, el primer paso es multiplicar Kg por 2.2. También hay una constante si una conversión también debe incluir un valor constante y la capacidad de crear múltiples pasos. Entonces, al convertir, digamos Celsius a Fahrenheit, multiplique Celsius por 1.8 y luego agregue 32. La clave sería de UOM, a UOM y el Paso de cálculo.

Ese es mi valor de 2 centavos. Espero que estas referencias le den una buena idea para pensar si alguna vez tiene la oportunidad de reiniciar el diseño actual.

Todd Everett
fuente
Gracias por pensar en algo muy interesante: aprendí mucho. Sin embargo, no creo que EAV sea el modelo apropiado en mi caso (si entiendo su sugerencia correctamente) porque, aunque tenemos cientos de columnas, de ninguna manera son escasas. Sin embargo, esto despertó una idea relacionada (ver ACTUALIZACIÓN en mi publicación original).
kmote
Su idea me suena bastante bien: no puedo pensar en otros problemas que no sean los que ya señaló. Pero si las columnas se pueden renombrar / cambiar, eso sería un problema en cualquier diseño. Esto es cuando la colaboración es divertida: ¡surge una idea en la que ninguno de nosotros pensó para empezar!
Todd Everett
8

Todo el trabajo.

Tenga en cuenta que en el segundo caso, no puede agregar manzanas y naranjas, por lo que los datos son excepcionalmente fáciles de someter a malas interpretaciones.

También tenga en cuenta que las conversiones no pueden ser muy seguras y son susceptibles a errores de redondeo, desbordamientos, etc.

Además, hay problemas físicos como la gravedad específica y la temperatura. Convertir 20 galones de agua en libras requeriría que conozca la densidad del agua. Pero la densidad del agua cambia con la temperatura, por lo que es posible que necesite conocer la densidad contemporánea a la medición o la temperatura de manera similar y usar un factor de corrección de volumen.

En el caso de las propiedades extendidas, eso solo es bueno para la documentación; un buen nombre de columna es mejor para la documentación. El problema con la columna implicada como estar en una unidad fija por nombre es que terminas arrinconándote cuando cambias las unidades de medida (el nuevo cliente quiere petróleo en barriles y no galones) y eso estaría bien ya que sus datos están en su propia base de datos, pero el nombre de la columna ahora es engañoso.

Otra opción es almacenar versiones canónicas en unidades fijas (es decir, siempre kilogramos y metros) además de las medidas originales variables. Las operaciones agregadas en las unidades fijas deberían estar bien (excepto que no agregaría temperaturas, por ejemplo), pero no pierde la medida original.

Cade Roux
fuente
1
La posible "mala interpretación" que usted menciona es exactamente una de las preocupaciones que tengo sobre la arquitectura actual de esta base de datos, y es algo que estoy tratando de encontrar una forma de reducir.
kmote
1
gran punto sobre el posible inconveniente de la solución de nombre de columna.
kmote
1
@kmote No es un problema simple: tenemos informes en los que las transacciones individuales pueden tener unidades de medida originales variables, pero también hay un total, que es un total después de la conversión a una unidad seleccionada por el usuario.
Cade Roux
7

Una solución simple que me ha funcionado bien en el pasado es almacenar todos sus datos en las unidades 'base'. Por ejemplo, su unidad base para longitudes puede ser milímetros y su unidad base para pesas puede ser kilogramos. Esta solución puede resultar en la necesidad de convertir algunos de sus datos existentes en la unidad base, si aún no lo ha hecho.

Una vez que tenga todos los datos en las unidades base estándar, no es necesario almacenar la unidad en la base de datos, ya que ahora es una suposición de todo el sistema. Las unidades que se muestran para cada tipo de unidad (por ejemplo, si se deben mostrar mm, pulgadas, cm, m de longitud) se convierten en un problema de dominio de aplicación / cliente, que se puede guardar en el almacenamiento local.

Las tablas de conversión de unidades para convertir entre las distintas unidades compatibles se pueden codificar dentro de su aplicación, ya que las nuevas unidades de medida cambian muy raramente.

Nota: una solución relacionada a otro problema es que cuando se almacenan marcas de tiempo en una base de datos para almacenarlas siempre en la unidad 'base' - UTC .

Otra Q&A relacionada sobre el tema ...

dodgy_coder
fuente
5

Como cualquier unidad se puede convertir a otra unidad del mismo tipo con la fórmula:

y = ((x + xOffset) * multiplicand / denominator) + yOffset

Crearía una tabla que contiene los tipos de unidades más estos 4 valores.

From Unit     To Unit      Unit Type    From Offset    Multiplicand    Denominator    To Offset
'milligrams'  'grams'      'mass'       0              1               1000           0
'grams'      'kilograms'   'mass'       0              1               1000           0
'grams'      'ounces'      'mass'       0              100000          2835           0
'ounces'     'pound'       'mass'       0              1               16             0

Después de haber agregado todas las mediciones que es probable que convierta ay desde cada lado de la lista, ejecute una Consulta donde inserte la operación inversa simplemente negando los desplazamientos e intercambiando el multiplicando y el denominador y la Unidad To y From Unit.

Para agregar la conversión entre todos los tipos, una unión cruzada con algunos filtros puede insertar las conversiones de reasignación.

peroyhav
fuente
3

Después de leer la respuesta de @Todd Everett, se me ocurrió una solución, así que voy a seguir adelante y responder mi propia pregunta. Lo que creo que voy a hacer es crear una separada ColumnUnitsmesa, con cuatro columnas: Schema, Table, Column, UnitsID(donde UnitsID es FK a una separada UnitsOfMeasurede mesa), la cartografía de este modo cualquier columna dada a su Unidad de medida asociado. Obviamente, el mayor inconveniente de esta idea es que los desarrolladores tendrían que recordar editar esta tabla cada vez que cambien el nombre de una columna o tabla [¿ quizás usen un disparador DDL ?], de lo contrario el sistema se romperá. Pero suponiendo que tales cambios de nombre sean raros, y que la tienda de desarrollo sea pequeña (solo una persona, en mi caso), esta arquitectura debería ser viable. La ventaja es que no se deben realizar cambios invasivos en la base de datos actual, y solo tengo que almacenar el valor una vez para cada columna, en lugar de una vez por fila, como lo requeriría mi segunda opción en mi publicación original.

kmote
fuente
rompecabezas interesante ... y una idea interesante que tienes. su idea facilitaría la consulta, pero no parece lograr mucho. acabas de mover los datos de referencia a un lugar diferente. lo que más me molesta de este diseño
Sir Swears-a-lot el
... es que si un elemento tiene más atributos, aún necesita agregar más columnas. Por esa razón, me gusta la sugerencia de @todd everett de un diseño eav.
Sir Swears-a-lot el