Melhor maneira de armazenar unidades no banco de dados

21

Eu herdei um banco de dados grande (SQLServer) com centenas de colunas que representam quantidades de uma coisa ou de outra. As unidades para esses valores (por exemplo, "galões", "polegadas" etc.) são armazenadas no campo MS_Description de Propriedades estendidas. Gostaria de saber se existe uma maneira melhor de armazenar essas informações. Suponho que seja bom para fins de documentação, mas seria difícil fazer cálculos robustos de conversão de unidades com base nesses dados. Neste ponto, não estou preparado para fazer uma mudança invasiva, mas se tiver a chance de fazê-lo, qual é a melhor prática recomendada a esse respeito? As opções, em cima da minha cabeça, podem incluir:

  • Altere o nome da coluna para as unidades incluídas (por exemplo, "TotalVolumeInGallons". Isso tornaria as informações um pouco mais prontamente disponíveis, mas ainda me parecem fracas.)
  • Adicione uma coluna "Unidades" separada para corresponder a todas as colunas "Quantidade" (essa coluna pode ser nvarchar OU pode ser uma chave estrangeira para uma tabela de unidades separada, o que pode facilitar o cálculo de conversões de unidades. muitas colunas podem dobrar bastante o tamanho do meu banco de dados - com dados terrivelmente redundantes.)
  • Crie um novo campo em Propriedades estendidas dedicado especificamente para unidades. (Infelizmente, acho que isso não pode ser uma chave estrangeira para uma tabela de unidades.)
  • Existe outra ideia que estou ignorando?

ATUALIZAÇÃO: Depois de ler a resposta de @Todd Everett, uma possível solução me ocorreu, então vou em frente e respondo minha própria pergunta. (Ver abaixo)

kmote
fonte
A melhor prática é ter um único sistema de medição usado de maneira universal e consistente em todo o aplicativo. SI seria o sistema de escolha. Os valores em outros sistemas serão convertidos durante o carregamento ou na camada de apresentação, onde cada usuário pode escolher seu conjunto preferido.
Michael Green

Respostas:

12

Como você menciona centenas de colunas, consideraria um design de EAV . Enquanto Joe Celko adverte contra isso , acho que pode ser aplicável no seu caso de uso. Parece que todos os seus "valores" são números, para evitar os problemas de elenco que Joe descreve e a necessidade de transformar cada "valor" em uma string. Funcionará ainda melhor se todos os valores forem números inteiros, mas também poderá funcionar se alguns forem decimais. Dadas as unidades de medida, você poderia dar um passo adiante e implementar um modelo de estilo "modelo de dados universal", baseado neste artigo de David Hay e também descrito em seu livro Padrões de modelo de dados: convenções de pensamento. Este modelo tem a vantagem adicional de configurar quais "valores" se aplicam a quais "itens", se você precisar. Uma etapa adicional mostrada no livro na página 162 é uma tabela de conversão de unidades de medida que você pode usar para converter entre as diferentes unidades de medida. Aqui está um exemplo:

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

Isto significa que para converter de Kg para Lb o primeiro passo é multiplicar Kg por 2,2. Também há uma constante se uma conversão também deve incluir um valor constante e a capacidade de criar várias etapas. Portanto, ao converter, digamos, Celsius para Fahrenheit, você multiplica Celsius por 1,8 e depois adiciona 32. A chave seria UOM, UOM e Etapa de cálculo.

Esse é o meu valor de 2 centavos. Espero que essas referências lhe permitam refletir bem, caso você tenha a chance de reiniciar o design atual.

Todd Everett
fonte
Obrigado por alguns pensamentos muito interessantes - eu aprendi muito. No entanto, não acho que o EAV seja o modelo apropriado no meu caso (se entendi sua sugestão corretamente) porque, embora tenhamos centenas de colunas, elas não são de forma alguma esparsas. No entanto, este DID desencadeou uma ideia relacionada (consulte UPDATE no meu post original).
kmote 30/05
Sua idéia me parece muito boa - não consigo pensar em nenhum outro problema além do que você já apontou. Mas se as colunas puderem ser renomeadas / alteradas, isso seria um problema em qualquer design. É quando a colaboração é divertida - surge uma idéia que nenhum de nós pensou em começar!
Todd Everett
8

Todo o trabalho.

Observe que, no segundo caso, você não pode adicionar maçãs e laranjas e, portanto, os dados são excepcionalmente fáceis de serem sujeitos a erros de interpretação.

Observe também que as conversões não podem ser muito seguras e são suscetíveis a erros de arredondamento, estouros excessivos etc.

Além disso, existem problemas físicos, como a gravidade e a temperatura específicas. Converter 20 galões de água em libras exigiria que você conhecesse a densidade da água. Mas a densidade da água muda com a temperatura; portanto, você pode precisar conhecer a densidade contemporânea da medição ou a temperatura da mesma forma e usar um fator de correção de volume.

No caso das propriedades Estendidas, isso é bom apenas para documentação - um bom nome de coluna é melhor para documentação. O problema com a coluna implicada como estando em uma unidade fixa pelo nome é que você acaba se esquecendo quando altera as unidades de medida - o novo cliente quer óleo em barris e não em galões - e isso seria bom, pois os dados estão em seu próprio banco de dados, mas o nome da coluna agora é enganoso.

Outra opção é armazenar versões canônicas em unidades fixas (ou seja, sempre quilogramas e metros), além das diversas medidas originais. As operações agregadas nas unidades fixas devem ser boas (exceto que você não adicionaria temperaturas, por exemplo), mas você não perde a medida original.

Cade Roux
fonte
1
A potencial "má interpretação" que você mencionou é exatamente uma das preocupações que tenho sobre a arquitetura atual desse banco de dados - e algo que estou tentando descobrir uma maneira de reduzir.
kmote
1
grande ponto sobre a desvantagem potencial da solução de nome da coluna.
kmote
1
@kmote Não é um problema simples - temos relatórios em que as transações individuais podem ter unidades de medida originais variadas, mas também há um total - que é um total após a conversão em uma unidade selecionada pelo usuário.
Cade Roux
7

Uma solução simples que funcionou bem para mim no passado é armazenar todos os seus dados nas unidades 'base'. Por exemplo, sua unidade base para comprimentos pode ser milímetros e sua unidade base para pesos pode ser quilogramas. Esta solução pode resultar na necessidade de converter alguns dos seus dados existentes na unidade base, se ainda não estiverem.

Depois de ter todos os dados nas unidades base padrão, não há necessidade de armazenar a unidade no próprio banco de dados, já que agora é uma suposição geral do sistema. As unidades exibidas necessárias para cada tipo de unidade (por exemplo, se deve exibir mm, polegadas, cm, m para comprimento) tornam-se um problema de domínio de aplicativo / cliente, que pode ser salvo no armazenamento local.

As tabelas de conversão de unidades para conversão entre as várias unidades suportadas podem ser codificadas no aplicativo, pois as novas unidades de medida mudam muito raramente.

NB, uma solução relacionada a outro problema é que, ao armazenar carimbos de data e hora em um banco de dados, os armazene sempre na unidade 'base' - UTC .

Outro Q&A relacionado sobre o tópico ...

dodgy_coder
fonte
5

Como qualquer unidade pode ser convertida em outra unidade do mesmo tipo Com a fórmula:

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

Eu criaria uma tabela que contém os tipos de unidade mais esses 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

Depois de adicionar todas as medidas que você provavelmente converterá de e para os dois lados da lista, execute uma Consulta na qual você insere a operação inversa simplesmente negando as compensações e trocando o multiplicando e o denominador e a Unidade To e From Unit.

Para adicionar conversão entre todos os tipos, uma junção cruzada Com alguns filtros, é possível inserir as conversões restantes.

peroyhav
fonte
3

Depois de ler a resposta de @Todd Everett, uma solução me ocorreu, então vou adiante e responder minha própria pergunta. O que eu acho que eu vou fazer é criar um separada ColumnUnitsmesa, com quatro colunas: Schema, Table, Column, UnitsID(onde UnitsID é FK a um separada UnitsOfMeasuremesa), mapeando assim, qualquer coluna para sua Unidade de medida associada. Obviamente, a maior desvantagem dessa idéia é que os desenvolvedores precisariam se lembrar de editar essa tabela sempre que renomearem uma coluna ou tabela [ talvez use um gatilho DDL ? ], caso contrário, o sistema irá quebrar. Mas, supondo que tais renomeações sejam raras, e a dev-shop pequena (apenas uma pessoa, no meu caso), essa arquitetura deve ser viável. A vantagem é que nenhuma alteração invasiva precisa ser feita no banco de dados atual, e eu só tenho que armazenar o valor uma vez para cada coluna, em vez de uma vez por linha, como exigiria minha segunda opção na postagem original.

kmote
fonte
quebra-cabeça interessante ... e idéia interessante que você tem. sua ideia facilitaria a consulta, mas parece não conseguir muito. você acabou de mover os dados de referência para um local diferente. o que mais me incomoda neste design
Sir Jura-muito-lote
... é que, se um item tiver mais atributos, você ainda precisará adicionar mais colunas. por esse motivo, eu gosto da sugestão de @todd everett de um design eav.
precisa saber é o seguinte