I'm trying to store a currency value in MySQL (InnoDb) and I need to write queries to aggregate some records (sum) and I'm having problem with the precision of the the output!
I've set the field's type to double and my values are some what precise but the MySQL's operators are not as precise as I need. For what it is worth, PHP's default operators are not precise enough either but there's bc* functions in PHP which can do the trick.
I was wondering if there's any way to tune the precision of MySQL operators? Including aggregation functions?
For the record, storing to and retrieving from MySQL won't affect my values which means double is an ideal type for my fields.
Since money needs an exact representation don't use data types that are only approximate like double which is a floating-point. You can use a fixed-point numeric data type for that like
numeric(15,2)
15 is the precision (total length of value including decimal places)
2 is the number of digits after decimal point
See MySQL Numeric Types:
These types are used when it is important to preserve exact precision, for example with monetary data.
Related
Is there any reason to use a DOUBLE(n, 0) over a BIGINT(n) in MySQL? If the data will never have a decimal portion, is there any reason to store as a DOUBLE?
There is only one reason to ever use DOUBLE or FLOAT in MySQL -- if scale and/or storage efficiency are important, but precision is not. This is not a limitation of MySQL, but rather of floating point numbers in general, which is that they are stored as approximate values.
Integers will be stored cleanly up to only about 2⁵³, which is smaller than BIGINT. Most (though not all) integers beyond that range will be stored as a value that is only close to correct.
Floating-point numbers sometimes cause confusion because they are approximate and not stored as exact values. A floating-point value as written in an SQL statement may not be the same as the value represented internally. Attempts to treat floating-point values as exact in comparisons may lead to problems. They are also subject to platform or implementation dependencies.
— Problems with Floating Point Values
For integers, use one of the *INT types. For decimal, use DECIMAL.
DECIMAL is supposed to be exact. It isn't. It rounds like crazy!
TABLE:
account_balance DECIMAL(18,4)
If I insert 43210987654321.9999
it rounds to 43210987654322.0000
If I insert 43210987654321.9876
it rounds to 43210987654321.9840
WHY? If I use numbers larger than 18 during table creation it is even worse.
EDIT:
I posted this clarification edit because some people do not know about the DECIMAL data type.
The DECIMAL data type is a FIXED POINT data type as opposed to a FLOATING POINT data type.
The reason it is used is:
(1) Store massive numbers that have decimal values with exact precision.
(2) Prevent rounding errors that can not be prevented when using floating point calculations. Thus any calculation on DECIMAL values should be exact... no rounding error.
POSTRESQL
http://www.postgresql.org/docs/8.1/static/datatype.html
numeric -- user-specified precision -- exact --no limit
The type numeric can store numbers with up to 1000 digits of precision and perform calculations exactly. It is especially recommended for storing monetary amounts and other quantities where exactness is required. However, arithmetic on numeric values is very slow compared to the integer types, or to the floating-point types described in the next section.
The types decimal and numeric are equivalent. Both types are part of the SQL standard.
MySQL
DECIMAL( , ) A DOUBLE stored as a string , allowing for a fixed decimal point.
http://www.htmlite.com/mysql003.php
MySQL DOC
Fixed-Point (Exact-Value) Types
The DECIMAL and NUMERIC types store exact numeric data values. These types are used when it is important to preserve exact precision, for example with monetary data. In MySQL, NUMERIC is implemented as DECIMAL, so the following remarks about DECIMAL apply equally to NUMERIC.
As of MySQL 5.0.3, DECIMAL values are stored in binary format. Previously, they were stored as strings, with one character used for each digit of the value.
http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html
The maximum value of 65 for M means that calculations on DECIMAL values are accurate up to 65 digits. This limit of 65 digits of precision also applies to exact-value numeric literals, so the maximum range of such literals differs from before. (In older versions of MySQL, decimal values could have up to 254 digits. However, calculations were done using floating-point and thus were approximate, not exact.)
Calculations involving exact-value decimal numbers are accurate to 65 digits. This is fewer than the maximum number of digits permitted before MySQL 5.0.3 (254 digits), but the exact-value precision is greater. Calculations formerly were done with double-precision floating-point, which has a precision of 52 bits (about 15 decimal digits).
http://dev.mysql.com/doc/refman/5.1/en/precision-math-decimal-changes.html
I tested on my local mysql 5.1.36 and it does not round.
What version are you using.
Also, what are you using to insert. Are you sure it is mysql rounding and not the storage before inserting to mysql.
I am setting up company pages. One of the fields is 'Revenue'. So this can vary from $0 to i guess hundreds of billions. So this field should have a bigint data type? Or is there a better way to store revenue in the database? Using MySQL.
Have a look at the DECIMAL data type.
I would use bigint and store your revenue figures in pennies rather than using decimals. Then you will avoid rounding issues.
Try Numeric or decimal. The DECIMAL and NUMERIC types store exact numeric data values. These types are used when it is important to preserve exact precision, for example with monetary data.
check this out: MySQL data types
A friend of mine said that they experienced oddities with using the decimal column to store money formats such as saving 1000.00 which would result in it being stored as 999.99.
However I just tested and 1000.00 is stored as 1000.0000 on decimal(19,4) / MySQL 5. Can anyone offer insight into why they may have experienced issues? Perhaps it was an old MySQL bug, improper calculation on the application side before saving it to the database?
This is for an ROI field and I'm storing money values which can be up in the thousands, FYI.
You should use the DECIMAL data type for exact numeric representations, and not DOUBLE. Quoting from the MySQL Documentation on Numeric Types:
MySQL supports all of the standard SQL numeric data types. These types include the exact numeric data types (INTEGER, SMALLINT, DECIMAL, and NUMERIC), as well as the approximate numeric data types (FLOAT, REAL, and DOUBLE PRECISION).
...
Because floating-point values are approximate and not stored as exact values, attempts to treat them as exact in comparisons may lead to problems. They are also subject to platform or implementation dependencies. For more information, see Section B.5.5.8, Problems with Floating-Point Values.
On 1.14.2. DECIMAL Data Type Changes where changes to the decimal type are discussed it says this:
In older versions of MySQL, decimal values could have up to 254 digits. However, calculations were done using floating-point and thus were approximate, not exact.
This could be the source of the error your friend talked about. If the value of 1000.00 was calculated it would be prone to floating point errors.
I would choose decimal for storing monetary values as the calculations will be more accurate than using double.
I am wondering what data type I should use for storing 11.1234 in mySql?
I am not sure if I should use varchar or int. There is also some decimal data types.
FLOAT or DECIMAL is probably best.
From the MySQL manual:
The FLOAT and DOUBLE data types are
used to represent approximate numeric
data values [...] The DECIMAL and
NUMERIC data types are used to store
exact numeric data values. In MySQL,
NUMERIC is implemented as DECIMAL.
These types are used to store values
for which it is important to preserve
exact precision, for example with
monetary data.