在数据库中存储单位的最佳方法


21

我继承了一个大型(SQLServer)数据库,其中包含数百个列,这些列代表一件事或另一件事的数量。这些值的单位(例如“加仑”,“英寸”等)存储在扩展属性的MS_Description字段中。我想知道是否有更好的方法来存储此信息。我认为这对于文档目的来说是很好的,但是很难基于此数据进行可靠的单位转换计算。目前,我还没有准备好进行侵入性更改,但是如果有机会,我在这方面建议的最佳实践是什么?在我头顶上方的选项可能包括:

  • 将列名称更改为包含的单位(例如,“ TotalVolumeInGallons”。这将使该信息更容易获得,但对我而言似乎仍然很薄弱。)
  • 添加一个单独的“单位”列以对应于每个“金额”列(此列可以是nvarchar,也可以是一个单独的“单位”表的外键,这可能使计算单位转换更加容易。许多列可以使我的数据库大小增加一倍-拥有非常冗余的数据。)
  • 在扩展属性中专门为单位创建一个新字段。(不幸的是,我认为这不是Units表的外键。)
  • 我还有其他想法要忽略吗?

更新:阅读@Todd Everett的答案后,我想到了一个可能的解决方案,所以我将继续回答自己的问题。(见下文)


最佳实践是在整个应用程序中普遍且一致地使用单个测量系统。SI将是首选系统。其他系统中的值将在加载期间或在表示层中转换,每个用户都可以在其中选择自己喜欢的集合。
Michael Green

Answers:


12

由于您提到了数百列,因此我将考虑采用EAV设计。尽管Joe Celko 对此提出警告,但我认为它可能适用于您的用例。听起来您的所有“数量”都是数字,所以您可以避免Joe描述的转换问题以及将每个“值”设置为字符串的需要。如果所有金额均为整数,则效果更好,但如果为十进制,则效果也更好。给定度量单位,您可以再进一步一步,并根据David Hay的这篇文章并在他的《数据模型模式:思想惯例》一书中概述的那样,实现“通用数据模型”样式模型。如果需要,此模型还具有配置哪些“数量”应用于哪些“物”的附加优点。第162页的书中显示的另一个步骤是“计量单位转换”表,您可以使用该表在不同的计量单位之间进行转换。这是一个例子:

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

这表示将Kg转换为Lb的第一步是将Kg乘以2.2。如果转换还必须包含一个常数值,并且具有创建多个步骤的能力,则也存在一个常数。因此,在将摄氏温度转换为华氏温度时,您需要将摄氏温度乘以1.8,然后再加上32。关键是从UOM,到UOM和计算步骤。

那是我2美分的价值。我希望这些参考文献能给您带来有益的思考,如果您有机会重新启动当前设计的话。


感谢您提供一些非常有趣的思考-我学到了很多东西。但是,我认为EAV在我的情况下不是合适的模型(如果我正确理解了您的建议),因为尽管我们确实有100列,但它们绝不是稀疏的。但是,此DID引发了一个相关的想法(请参阅我的原始帖子中的UPDATE)。
kmote 2012年

您的想法对我来说听起来很不错-除了您已经指出的内容之外,我无法想到任何其他问题。但是,如果可以重命名/更改列,则在任何设计中都会出现问题。这是协作很有趣的时候-一个想法浮出水面,我们俩都没有想到!
托德·埃弗里特

8

所有的工作。

请注意,在第二种情况下,您无法添加苹果和橙子,因此数据异常容易被误解。

另请注意,转换并非十分安全,并且容易产生舍入错误,溢出等现象。

此外,还有一些物理问题,例如比重和温度。将20加仑水转换为磅,需要您知道水的密度。但是水的密度会随温度而变化,因此您可能需要类似地知道测量时的密度或温度,并使用体积校正因子。

在扩展属性的情况下,这仅对文档有用-好的列名对文档更好。该列的名称隐含在固定单位中的问题是,当您更改度量单位时,最终会陷入困境-新客户想要的是桶装而不是加仑的油,这很好,因为他们的数据在它自己的数据库,但列名现在具有误导性。

另一种选择是将标准版本以固定的单位(即,始终以千克和米为单位)存储,除了变化的原始测量值。在固定单位上进行汇总操作应该很好(例如,除非您不添加温度),但是您不会丢失原始测量值。


1
您提到的潜在“误解”恰恰是我对该数据库当前体系结构所关心的问题之一,而我正在尝试找出一种减少这种方法的方法。
kmote 2012年

1
关于列名解决方案潜在缺点的要点。
kmote 2012年

1
@kmote这不是一个简单的问题-我们有报告,其中每个交易可能具有不同的原始计量单位,但也有总计-转换为用户选择的单位后的总计。
卡德·鲁

7

过去对我有效的一个简单解决方案是将所有数据存储在“基本”单位中。例如,长度的基本单位可能是毫米,而重量的基本单位可能是千克。此解决方案可能需要将某些现有数据转换为基本数据(如果尚未转换)。

一旦所有数据都以标准基本单位为单位,就无需将其存储在数据库本身中,因为现在这是系统范围的假设。每种单位类型所需的显示单位(例如,是否显示长度的毫米,英寸,厘米,米)成为应用程序/客户端域问题,可以保存到本地存储中。

可以在您的应用程序中对用于在各种支持的单位之间进行转换的单位转换表进行硬编码,因为新的度量单位很少更改。

注意,另一个问题的相关解决方案是将时间戳存储在数据库中时始终将其存储在“基本”单元-UTC中

有关该主题的另一个相关问答...


5

由于可以使用以下公式将任何单位转换为相同类型的另一个单位:

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

我将创建一个包含单元类型以及这4个值的表。

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

添加完所有可能要转换的度量后,在列表的任一侧运行查询,在其中插入反运算,只需简单地抵消偏移量并交换被乘数和分母以及“到单位”和“从单位”。

要在所有类型之间添加转化,使用某些过滤器的交叉联接可以插入剩余的转化。


3

阅读@Todd Everett的答案后,我想到了解决方案,因此我将继续回答我自己的问题。我想我要做的就是创建一个单独的ColumnUnits表,四列:SchemaTableColumnUnitsID(其中UnitsID是FK到一个单独的UnitsOfMeasure表),从而映射任何给定列到其相关的计量单位。显然,此想法的最大缺点是,开发人员在重命名列或表时必须记住要编辑此表(也许使用DDL触发器],否则系统将崩溃。但是,假设这样的重命名很少,并且开发商店很小(在我的情况下,只有一个人),那么这种架构应该是可行的。优点是无需对当前数据库进行任何侵入式更改,并且我只需要为每列存储一次值,而不是为每行一次存储值,这是我在原始帖子中的第二种选择。


有趣的难题...以及您有有趣的想法。您的想法将使查询变得更容易,但似乎没有太大的作用。您刚刚将参考数据移到了其他位置。什么最困扰我的这个设计
爵士发誓一批量

...就是如果一个项目具有更多属性,您仍然需要添加更多列。因此,我喜欢@todd everett提出的eav设计建议。
Swears-a-lot爵士,2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.