Storing currency values in MySQL database - mysql

This question has been asked many times before, but I've found conflicting opinions on the topic so I thought I would bring it up again in hopes of a more unified conclusion.
I would like to store a currency value in my database. Let's assume all entries are the same type of currency (USD for example) and that both positive and negative values are allowed.
My initial thought would be to store the value as a signed integer in terms of the smallest unit of the associated currency. For example, if I want to store the value $1.25, I would insert 125 into the database, since the smallest unit of USD is $0.01. The nice thing about this method is that MySQL will automatically round to the nearest integer. For example, if the dollar value is $1.259, I could insert 125.9, which would automatically be rounded and stored as 126 or $1.26.
So, what do you think? Is this a sound approach or is there a better way?

Financial data can be stored as DECIMAL(p,s) where p is the number of significant digits, and s is the scale (number of places to the right of the decimal point). See The MySQL documentation.
Also from O'Reilly's High Performance MySQL, chapter 3:
"...you should use DECIMAL only when you need exact results for
fractional numbers--for example, when storing financial data."
From O'Reilly's Learning MySQL:
DECIMAL is, "...A commonly used numeric type. Stores a fixed-point
number such as a salary or distance..."
And MySQL Pocket Reference:
DECIMAL "...Stores floating-point numbers where precision is
critical, such as for monetary values."

There is nothing wrong with the approach you describe. There is no right or wrong when it comes to this question.
You have to keep in mind that to display a $ value to the user, you would need to always do a division operation or some kind of formatting.
Will it be easier to debug your formulas/calculations if everything was in cents or dollars? Will you be displaying the values in cents or dollars? etc.
Keep it simple, but either way you'll have to use a decimal.

Related

Microsoft Access Automatically Increase Decimal

Hi My Fellow Access user.
I am using Access to do reconciliation, by link two Excel sheets. the number are two decimal.
Linked Table view
However, when i was trying to run subtraction between two numbers both 2 decimals, it return results like this:
Appreciate if anyone know how this could happen, and what steps I need to take to fix it?
Thanks
Tian
Don't use the linked Excel data directly.
Create simple select queries where you can convert and trim your data. Like:
Select SomeField, Description, CCur([TotalAmount]) As Total
From YourLinkedExcelTable
When dealing with amounts, always use Currency as data type.
Now, calculate your Diff using the query.
For a linked Excel sheet, the column type is probably Double, a 64-bit floating point number. This problem you experience is probably due to an inherent limitation of floating point numbers and is not unique to Excel or Access.
This Stack Overflow question asks essentially the same thing: Why does this subtraction not equal zero?
Excel is no exception, only that the default formatting might not show the necessary precision to reveal the behavior. Selecting scientific format or increasing the number of displayed decimal places will reveal the same behavior.
Consider the following:
For monetary amounts, convert values to Currency using the CCur() function. Currency is a fixed-decimal value, but be aware it only has 4 digits to the right of the decimal. (Updated to reflect advice from Gustav)
Convert values to fixed-point Decimal type using CDec() function before performing the math. There is no native VBA Decimal type, so these are variants containing Decimal values. But upon conversion back to floating-point, it is still possible to experience extra digits.
Round the results using the Round() function, but again this is not guaranteed to eliminate floating-point limitations.
Choose an explicit format for displaying the numbers.

MySQL field type for weight and height data

What is the adequate MySQL field type for weight (in kilograms) and height (meters) data?
That all depends. There are advantages and disadvantages to the different numeric types:
If you absolutely need the height/weight to be exactly a certain number of decimal places and not subject to the issues that floating point numbers can cause, use decimal() (decimal takes two parameters, the amount number of digits > 1 and the number of digits < 1, so decimal(5,2) would be able to store numbers as low as 0.01 and as high as 999.99). Fixed precision math is a bit slower, and it's more costly to store them because of the algorithms involved in doing it. It's absolutely mandatory to store currency values or any value you intend to do math with involving currency as a numeric(). If you're, for instance, paying people per pound or per meter for a baby, it would need to be numeric().
If you're willing to accept the possibility that some numeric values will be less precise than others use either FLOAT or DOUBLE depending on the amount of precision and the size of the numbers you're storing. Floating points are approximations based on the way computers do math, we use decimal points to mean out of powers of 10, computers do math in base2, the two are not directly comparable, so to get around that algorithms were developed for cases in which 100% precision is not required, but more speed is necessary that cannot be achieved by modeling it using collections of integers.
For more info:
http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html
http://dev.mysql.com/doc/refman/5.0/en/fixed-point-types.html
http://dev.mysql.com/doc/refman/5.0/en/floating-point-types.html

How to store 1/3 as a decimal in MySQL

I am trying to figure out how to store 1/3, or any fraction which results in an infinitely repeating decimal value in MySQL. I cannot just use 3.333333 because it obviously does not total to 100. I have been reading about the float datatype but i'm not sure if this will work. Any help would be appreciated.
Thank you
You could potentially represent all rational numbers (including integers) as "numerator" and "denominator". So in your table you'd have a numerator and denominator columns, and your app would have logic to store numbers using that form.
You would still be unable to store irrational numbers precisely with this technique (i.e. if you want to store Pi, you'd need a fractional approximation anyway).
See here for what rational numbers are, so you can understand the limitations of this technique.
http://en.wikipedia.org/wiki/Rational_number
Store the numerator and the denominator in separate columns. It's really that simple. The real problem comes later when you want to add up all the fractions. Some languages have built-in facilities to do so, but I don't think MySQL does.

Do modern floating point implementations handle exact units (like money) well?

I am being specific about handling large number of money values. Each value is precise only upto 2 decimal places. But the values will be passed around by a database and one or more web frameworks and there will be arithemetic operations.
Should I insist on decimal datatypes for numbers that need only 2 places of precision? Or are modern floating point implementations robust and standardized to avoid it?
Hell no, absolutely, and the issues are orthogonal, in that order. :-)
Floating point numbers, especially in binary, are never the right choice for fixed-point quantities, least of all those that expect precise fractions, like money values. First of all, they don't express all values of cents (or whatever fractional component) accurately, just like fixed-length decimal numbers can't express 1/3 correctly. Secondly, adding or subtracting small and very large floating point numbers doesn't always produce the result you expect, because of differences in "significance".
Decimal numbers are the way to go for currency calculations. If you absolutely must use binary numbers, use scaled fixed-point binary numbers - for example, compute everything in 1/100ths of your currency unit, and use binary integers to do it.
Lastly, this has nothing to do with "robustness" or "standardization" - it's got everything to do with picking a datatype that matches your data.
No, they are not precise enough. See the floating point guide for details.

PHP: MySql Data Type for monetary values

What is the best way to store monetary values in MySql.
I've seen this: decimal(5,2)
but then you can't enter in more than $999.99 for the amount. I mean I know you can change the 5 to something else but this doesn't seem like the most appropriate way to do this.. then again I'm not sure that's why I'm posting.
I've also seen storing the amount as an unsigned int too. So what's the most efficient way to store monetary values?
How big a currency value do you anticipate that you need to store? DECIMAL(15,2) would handle what most will throw at it.
I've also seen storing the amount as an unsigned int too.
Unsigned means the value will never be negative -- you'd need additional means to indicate the value is meant to be negative if such is the case. I don't recommend this approach.
Your decision will have to include how you perform rounding. Businesses tend to round cents in their favour, whereas mathematical rounding might be preferred, as well as not caring at all. These may have a bearing on your storage choice.
And what about currency? If you want to support distributed clients in multiple locales, you'll need to embed the currency / locale of each monetary value. How do other DBs handle this?
For signed-integer values, it is a business decision to decide what is the "minimum value of interest" (do you care about 0.001c? This means that you don't mind losing 1c over 1000 sequential transactions - this is also important in calculating interest on low values, for example). If 0.001c is OK, then multiply all values by 1000 when you write to the table, divide by 1000 when you read them back...
Why not save the value in the lowest possible unit and let your script do the conversion to the usual representation?
That way you could store the value as an integer.