我应该如何向用户提供成本字段,并将其存储在数据库中?

时间:2009-04-29 17:08:09

标签: ruby-on-rails ruby database

现在我有两个成本领域。一个用于美元,一个用于美分。这有效,但有点难看。它也不允许用户输入术语“免费”或“无成本”,如果他们想要的话。但是如果我只有一个字段,我可能需要让我的解析器更聪明一些。你觉得怎么样?

在服务器端,我将美元和美分结合起来将它们存储为数据库中的小数。主要是为了让我能够快速收集统计数据(成本平均等)。

您认为将费用存储为字符串会更好吗?然后每当我实际使用统计数据或其他目的的成本时,我会在那时将其转换为小数。还是我走在正确的轨道上?

6 个答案:

答案 0 :(得分:8)

数据库设计中有一条规则规定不应拆分“原子数据”。通过这个规则,价格或成本就是原子数据的一个例子,因此它永远不应该分成多个列,就像你不应该在多个列之间拆分一个电话号码一样(除非你真的有很好的理由 - 非常罕见)

使用DECIMAL数据类型。像DECIMAL(8,3)这样的东西应该可以运行,所有符合ANSI SQL的数据库产品都支持它!

您可以参考Joe Celko的"Thinking In Sets"一书来讨论此主题。请参阅section 1.6.2, pages 21-22

编辑 - 从您的问题看来,您还关注如何以类似于价格(xxxx.xx)的形式接受用户的输入 - 因此两个输入框,全部美元和便士。

我建议使用单个输入框然后使用正则表达式进行输入验证以匹配您的格式(例如 [0-9] +(。[0-9] {1,3} )? 可能会有效,但可以改进)。然后,您可以将验证的字符串解析为您的语言中的Decimal类型,或者只是将其作为字符串传递到数据库中 - SQL将知道如何将其转换为DECIMAL类型。

答案 1 :(得分:4)

将整个成本保持为十进制。如果它是免费的,那么将成本保持为0.在演示中,如果成本为零 - 写“免费”而不是0.

答案 2 :(得分:2)

我通常将成本存储为最低单位(便士),然后将其转换为全美元。

所以4.50美元的成本被存储为450.免费项目将是-1便士。您可以将免费物品存储为0便士,这使您可以灵活地使用0和-1来表示两种稍微不同的东西(免费与不销售?)。

如果您选择走这条路线,它也可以更容易地支持那些不使用美分的国家。


至于呈现数据输入字段,我个人不喜欢它,因为我必须保持切换字段的小事情(例如当他们将电话号码分成3个字段,或IP地址分成4个字段时)。我将呈现一个字段,让用户自己键入小数点。这样,您的用户就不必使用标签(或点击,如果他们不熟悉标签页)到下一个字段。

答案 3 :(得分:2)

使用美分,使用450美元4.50美元,这将为您节省经常出现的问题 从浮点运算不安全的事实。只需在irb中尝试以下表达式: 0.4 - 0.3 == 0.1将返回false。都是因为浮点表示 innacuracies。

在我的模特中,我一直在使用:

attr_accessor :price_with_cents
def price_with_cents
  self.price/100.00
end

def price\_with\_cents==(num)
  self.price = (num.to_f * 100.00).to_i
end

列的名称只是价格整数类型。

我没有太多关于十进制列及其在ruby中的表示的经验(可能是浮动,这是有问题的,因为我在开始时显示)。

答案 4 :(得分:0)

不要让垃圾进入您的数据库。如果你期望一个字段上有一个美元金额,那么确保它在进入之前是有效的。这将允许您更好地报告数据并允许更简单的输出格式。

我建议将此字段作为更新或插入验证的单个字段。

if field != SpecialFreeTag then

  try to convert to decimal
    if fail then report to user
    otherwise accept value

使用try parse或正则表达式来帮助验证。

答案 5 :(得分:0)

我会将成本存储为十进制,其中刻度不小于2,甚至可能是3-5。如果批量购买某些东西,单位成本可能很容易包含一分钱。免费项目的成本为0.如果成本未知,则也允许空值。