[英]How should I present a cost field to the user, and store it in the database?
現在,我有兩個成本領域。 一美元,一美分。 這行得通,但是有點難看。 它還不允許用戶根據需要輸入術語“免費”或“免費”。 但是,如果我只有一個字段,則可能必須使解析器更加智能。 你怎么看?
在服務器端,我將美元和美分結合起來以小數形式存儲在數據庫中。 主要是為了使我可以快速收集統計信息(平均費用等)。
您認為將成本存儲為字符串更好嗎? 然后,無論何時我將成本實際用於統計或其他目的,都將在那一刻將其轉換為小數。 還是我步入正軌?
數據庫設計中有一條規則規定“原子數據”不應拆分。 根據此規則,價格或成本就是原子數據的示例,因此,永遠不要將其拆分為多列,就像您不應將電話號碼拆分為多列一樣(除非您確實有很好的理由-極少)
使用DECIMAL數據類型。 像DECIMAL(8,3)這樣的東西應該可以工作,並且所有符合ANSI SQL的數據庫產品都支持它!
您可以查閱Joe Celko的“思維定型”書中有關此主題的討論。 請參閱第1.6.2節,第21-22頁 。
編輯 -從您的問題看來,您還擔心如何以類似於價格(xxxx.xx)的形式接受用戶輸入-因此有兩個輸入框,代表整個美元和便士。
我建議使用單個輸入框,然后使用正則表達式進行輸入驗證以匹配您的格式(例如[0-9] +(。[0-9] {1,3}))可能會起作用,但可以改進)。 然后,您可以使用您的語言將經過驗證的字符串解析為Decimal類型,或者僅將其作為字符串傳遞給數據庫-SQL將知道如何將其轉換為DECIMAL類型。
將總成本保持為小數。 如果是免費的,則將成本保持為0。在演示中,如果成本為零,請寫成“免費”而不是0。
我通常將成本存儲為最低單位(便士),然后將其轉換為整美元。
因此,將4.50美元的成本存儲為450。免費商品將為-1便士。 您也可以將免費商品存儲為0便士,這使您可以靈活地使用0和-1來表示兩個稍有不同的商品(免費還是不出售?)。
如果您選擇沿途使用美分,也可以更輕松地支持不使用美分的國家。
至於顯示數據輸入字段,我個人不喜歡它,因為我不得不為微小的事情保持切換狀態(例如當他們將電話號碼分為3個字段,或者將IP地址分為4個字段時)。 我將顯示一個字段,然后讓用戶自己輸入小數點。 這樣,您的用戶就不必跳至下一個字段(如果不熟悉此選項卡,也可以單擊)。
使用美分,使用450的價格為$ 4.50,這將為您節省因浮點操作不安全而經常引起的問題。 只需在irb中嘗試以下表達式:0.4-0.3 == 0.1將返回false。 都是因為浮點表示不准確。
在我的模型中,我一直使用:
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中的表示沒有太多經驗(可以是浮點數,如我一開始所顯示的那樣是有問題的)。
不允許垃圾進入您的數據庫。 如果您期望某個字段上有美元,那么在進入該字段之前,請確保它是有效的。 這將使您可以更好地報告數據,並可以簡化輸出格式。
我建議將此字段設為對更新或插入進行驗證的單個字段。
if field != SpecialFreeTag then
try to convert to decimal
if fail then report to user
otherwise accept value
使用try解析或正則表達式可以幫助進行驗證。
我將成本存儲為小數位數,其比例應不小於2,甚至是3-5。 如果大量購買某物,則單位成本很容易包含零點幾分。 免費商品的成本為0。如果成本未知,則還允許使用空值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.