J'ai hérité d'une grande base de données (SQLServer) avec des centaines de colonnes qui représentent des quantités d'une chose ou d'une autre. Les unités de ces valeurs (par exemple "gallons", "pouces", etc.) sont stockées dans le champ MS_Description des propriétés étendues. Je me demande s'il existe une meilleure façon de stocker ces informations. Je suppose que c'est bien à des fins de documentation, mais il serait difficile de faire des calculs de conversion d'unité robustes sur la base de ces données. À ce stade, je ne suis pas prêt à effectuer un changement invasif, mais si j'en ai l'occasion, quelle est la meilleure pratique recommandée à cet égard? Les options, du haut de ma tête, pourraient inclure:
- Changez le nom de la colonne en unités incluses (par exemple, "TotalVolumeInGallons". Cela rendrait les informations un peu plus facilement disponibles, mais elles me semblent encore faibles.)
- Ajoutez une colonne "Unités" distincte pour correspondre à chaque colonne "Montant" (cette colonne peut être nvarchar OU il peut s'agir d'une clé étrangère vers une table Unités distincte qui pourrait faciliter le calcul des conversions d'unités. Par contre, l'ajout de de nombreuses colonnes pourraient doubler la taille de ma base de données - avec des données terriblement redondantes.)
- Créez un nouveau champ dans les propriétés étendues dédié spécifiquement aux unités. (Malheureusement, je ne pense pas que cela puisse être une clé étrangère vers une table d'unités.)
- Y a-t-il une autre idée que j'écarte?
MISE À JOUR: Après avoir lu la réponse de @Todd Everett, une solution possible m'est venue, alors je vais aller de l'avant et répondre à ma propre question. (Voir ci-dessous)
Réponses:
Puisque vous mentionnez des centaines de colonnes, je considérerais une conception EAV . Alors que Joe Celko met en garde contre cela , je pense que cela peut être applicable dans votre cas d'utilisation. Il semble que tous vos "montants" soient des nombres, vous éviterez ainsi les problèmes de casting que Joe décrit et la nécessité de faire de chaque "valeur" une chaîne. Cela fonctionnera encore mieux si tous les montants sont des nombres entiers, mais peut également fonctionner si certains sont décimaux. Compte tenu des unités de mesure, vous pourriez aller plus loin et mettre en œuvre un modèle de style "modèle de données universel" basé sur cet article de David Hay et également décrit dans son livre Data Model Patterns: Conventions of Thought. Ce modèle a l'avantage supplémentaire de configurer quels «montants» s'appliquent à quelles «choses» si vous en avez besoin. Une étape supplémentaire indiquée dans le livre à la page 162 est un tableau de conversion d'unité de mesure que vous pouvez utiliser pour convertir entre les différentes unités de mesure. Voici un exemple:
Cela signifie que pour convertir de Kg en Lb, la première étape consiste à multiplier Kg par 2,2. Il existe également une constante si une conversion doit également inclure une valeur constante et la possibilité de créer plusieurs étapes. Ainsi, lors de la conversion, dites Celsius en Fahrenheit, vous multipliez Celsius par 1,8, puis ajoutez 32. La clé serait le de UOM, le à UOM et l'étape de calcul.
C'est ma valeur de 2 cents. J'espère que ces références vous donneront matière à réflexion si jamais vous avez la possibilité de redémarrer le design actuel.
la source
Tout le travail.
Notez que dans le deuxième cas, vous ne pouvez pas ajouter de pommes et d'oranges, et donc les données sont exceptionnellement faciles à faire l'objet d'une mauvaise interprétation.
Notez également que les conversions ne peuvent pas être très sûres et sont susceptibles d'erreurs d'arrondi, de débordements, etc.
De plus, il y a des problèmes physiques comme la gravité spécifique et la température. Pour convertir 20 gallons d'eau en livres, il vous faudrait connaître la densité de l'eau. Mais la densité de l'eau change avec la température, vous devrez donc peut-être connaître la densité contemporaine à la mesure ou la température de manière similaire et utiliser un facteur de correction de volume.
Dans le cas des propriétés étendues, ce n'est bon que pour la documentation - un bon nom de colonne est préférable pour la documentation. Le problème avec la colonne implicite comme étant dans une unité fixe par nom est que vous finissez par vous mettre dans un coin lorsque vous changez d'unités de mesure - un nouveau client veut du pétrole en barils et non en gallons - et ce serait bien puisque leurs données sont en sa propre base de données, mais le nom de la colonne est maintenant trompeur.
Une autre option consiste à stocker les versions canoniques dans des unités fixes (c'est-à-dire toujours des kilogrammes et des mètres) en plus des mesures originales variables. Les opérations d'agrégation sur les unités fixes devraient être correctes (sauf que vous n'ajouteriez pas de températures, par exemple), mais vous ne perdez pas la mesure d'origine.
la source
Une solution simple qui a bien fonctionné pour moi dans le passé consiste à stocker toutes vos données dans les unités «de base». Par exemple, votre unité de base pour les longueurs peut être en millimètres et votre unité de base pour les poids peut être en kilogrammes. Cette solution peut entraîner la nécessité de convertir certaines de vos données existantes dans l'unité de base, si ce n'est pas déjà fait.
Une fois que vous avez toutes les données dans les unités de base standard, il n'est pas nécessaire de stocker l'unité dans la base de données elle-même, car il s'agit désormais d'une hypothèse à l'échelle du système. Les unités affichées requises pour chaque type d'unité (par exemple, s'il faut afficher mm, pouces, cm, m pour la longueur) devient un problème de domaine d'application / client, qui peut être enregistré sur le stockage local.
Les tables de conversion d'unité pour la conversion entre les différentes unités prises en charge peuvent être codées en dur dans votre application, car les nouvelles unités de mesure changent extrêmement rarement.
NB une solution connexe à un autre problème est que lors du stockage d'horodatages dans une base de données pour toujours les stocker dans l'unité «de base» - UTC .
Un autre Q&A connexe sur le sujet ...
/programming/12977021/best-practice-for-storing-weights-in-a-sql-database
Cela contient de bonnes informations sur les raisons pour lesquelles l'utilisation d'un type de colonne à virgule flottante est la meilleure solution lorsque vous stockez des mesures du monde réel.
la source
Étant donné que toute unité peut être convertie en une autre unité du même type Avec la formule:
Je créerais une table qui contient les types d'unités plus ces 4 valeurs.
Après avoir ajouté toutes les mesures que vous êtes susceptible de convertir vers et à partir de chaque côté de la liste, exécutez une requête dans laquelle vous insérez l'opération inverse en annulant simplement les décalages et en échangeant le multiplicande et le dénominateur et les unités À et À partir de l'unité.
Pour ajouter une conversion entre tous les types, une jointure croisée avec certains filtres peut insérer les conversions restantes.
la source
Après avoir lu la réponse de @Todd Everett, une solution m'est venue à l'esprit, alors je vais continuer et répondre à ma propre question. Ce que je pense que je vais faire est de créer une séparée
ColumnUnits
table, avec quatre colonnes:Schema
,Table
,Column
,UnitsID
(où UnitsID est FK à un séparéUnitsOfMeasure
tableau), la cartographie ainsi une colonne donnée à son unité de mesure associée. De toute évidence, le plus gros inconvénient de cette idée est que les développeurs devraient se souvenir de modifier cette table chaque fois qu'ils renomment une colonne ou une table [ peut-être utiliser un déclencheur DDL ? ], sinon le système se cassera. Mais en supposant que de tels renommages sont rares et que le dev-shop soit petit (une seule personne, dans mon cas), cette architecture devrait être réalisable. L'avantage est qu'aucune modification invasive ne doit être apportée à la base de données actuelle, et je n'ai à stocker la valeur qu'une seule fois pour chaque colonne, plutôt qu'une fois par ligne, comme ma deuxième option dans mon message d'origine l'exigerait.la source