ChatGPT解决这个技术问题 Extra ChatGPT

Best data type to store money values in MySQL

I want to store many records in a MySQL database. All of them contains money values. But I don't know how many digits will be inserted for each one. Which data type do I have to use for this purpose? VARCHAR or INT (or other numeric data types)?

deimal(10,2) is what i use ... you can adjust the values depending on size expected
Related question is Best Data Type for Currency ;).

j
juergen d

Since money needs an exact representation don't use data types that are only approximate like float. You can use a fixed-point numeric data type for that like

decimal(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.


what could be the difference between decimal and numeric data type for this case?
In MySQL decimal and numeric are the same.
I personally use numeric(19,4) for financial records that gives you a better hand to play and adopt new requests easily.
I agree with YahyaE, more decimals is better. There are some currencies that typically use 3 decimal places, such as the Bahraini, Jordanian, or Kuwaiti Dinars, so you need at least 3. Four or five is better.
@EdwinHoogerbeets Not being an accountant... but running a small biz in the UK... I remember reading somewhere a long time ago that currency figures should be stored to 4 decimals even for £, $, etc. so that certain calculations might actually use the last 2 decimal places for certain obscure accounting contexts. Wd need an accountant to confirm/refute.
N
NullPoiиteя

You can use DECIMAL or NUMERIC both are same

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. : MySQL

i.e. DECIMAL(10,2)

Good read


I am using decimal(10,2) for my money value, however when I put something like 867,000.00 it gets saved as 867. what am I doing wrong?
@codeinprogress you have a comma in your money value...if it goes into the database that same way. Mysql will truncate starting from the comma position
s
shA.t

I prefer to use BIGINT, and store the values in by multiply with 100, so that it will become integer.

For e.g., to represent a currency value of 93.49, the value shall be stored as 9349, while displaying the value we can divide by 100 and display. This will occupy less storage space.

Caution: Mostly we don't perform currency * currency multiplication, in case if we are doing it then divide the result with 100 and store, so that it returns to proper precision.


I remember being told a similar thing by a professor on my Computer Systems university course. I was taught the most precise way is to store in pennies (or cent) by multiply by 100 and saving as an Integer and dividing by 100 to display it to the user. I guess this has benefits in terms of accuracy and performance of the database system.
What is the advantage over DECIMAL? You create a need to translate pennies to dollars, and woe if you forget it at some point.
Space is the only advantage, but yes we need to be more careful when we are using this feature.
In case it's not obvious: be wary of using the scale removing method if you store money in fractional cents (e.g., $0.005 or $0.12345) because they will not reduce to an integer after multiplying by 100. If you know the precision of the values it's clear the best option is to use DECIMAL. But if you don't know the precision (as in my examples) then…would FLOAT be appropriate?
An advantage of this method comes when using a language like JavaScript that uses IEEE-754 to store floating point numbers. This specification does not guarantee that 0.1 + 0.2 === 0.3 is true. Storing currency as an integer gives certainty that your application will not incur that kind of error. This may not be the best solution though. I arrived at this page while researching solutions and I'm not done yet.
S
Svetoslav

It depends on your need.

Using DECIMAL(10,2) usually is enough but if you need a little bit more precise values you can set DECIMAL(10,4).

If you work with big values replace 10 with 19.


I am using decimal(10,2) for my money value, however when I put something like 867,000.00 it gets saved as 867. what am I doing wrong?
@codeinprogress Using the wrong locale/decimal separator?
@codeinprogress You are using the , for digit grouping. Do not do that. Never use comma or point for digit grouping.
d
david.ee

If your application needs to handle money values up to a trillion then this should work: 13,2 If you need to comply with GAAP (Generally Accepted Accounting Principles) then use: 13,4

Usually you should sum your money values at 13,4 before rounding of the output to 13,2.


If you're going to take Bitcoin, you're going to need 8 decimal places, although most wallets go to mBTC which is 3 en.wikipedia.org/wiki/Bitcoin
Don't think this answer is true. opendata.stackexchange.com/a/10348/13983 @david.ee got a source for that?
@EvanCarroll let me answer for david.ee. I think this article may be the source rietta.com/blog/2012/03/03/best-data-types-for-currencymoney-in
@naXa the link does not quote anything from any source that support's the claim of using 13,4 for GAAP. All you did was link to an article that makes the same unsubstantiated claim.
b
bizwiz

At the time this question was asked nobody thought about Bitcoin price. In the case of BTC, it is probably insufficient to use DECIMAL(15,2). If the Bitcoin will rise to $100,000 or more, we will need at least DECIMAL(18,9) to support cryptocurrencies in our apps.

DECIMAL(18,9) takes 12 bytes of space in MySQL (4 bytes per 9 digits).


> A bitcoin can be divided down to 8 decimal places. Therefore, 0.00000001 BTC is the smallest amount that can be handled in a transaction. I think you mean 8 instead of 9?
I know, but 9 takes the same disk space as 8. From MySQL docs: "Values for DECIMAL columns are stored using a binary format that packs nine decimal digits into 4 bytes"
Ow sorry, now I get you. Thanks.
a
antak

We use double.

*gasp*

Why?

Because it can represent any 15 digit number with no constraints on where the decimal point is. All for a measly 8 bytes!

So it can represent:

0.123456789012345

123456789012345.0

...and anything in between.

This is useful because we're dealing with global currencies, and double can store the various numbers of decimal places we'll likely encounter.

A single double field can represent 999,999,999,999,999s in Japanese yens, 9,999,999,999,999.99s in US dollars and even 9,999,999.99999999s in bitcoins

If you try doing the same with decimal, you need decimal(30, 15) which costs 14 bytes.

Caveats

Of course, using double isn't without caveats.

However, it's not loss of accuracy as some tend to point out. Even though double itself may not be internally exact to the base 10 system, we can make it exact by rounding the value we pull from the database to its significant decimal places. If needed that is. (e.g. If it's going to be outputted, and base 10 representation is required.)

The caveats are, any time we perform arithmetic with it, we need to normalize the result (by rounding it to its significant decimal places) before:

Performing comparisons on it. Writing it back to the database.

Another kind of caveat is, unlike decimal(m, d) where the database will prevent programs from inserting a number with more than m digits, no such validations exists with double. A program could insert a user inputted value of 20 digits and it'll end up being silently recorded as an inaccurate amount.


First time I've seen an answer like this, interesting. Q: If I write a float like 1.41 to the database and for some reason I need to multiply it by some huge number in mysql, like 1.000.000.000.000. Will the rounded result exactly be: 1.410.000.000.000?
@roelleor For the result to be exactly 1,410,000,000,000 (comma as thousands separator) the input is assumed to be 1.410000000000 (twelve significant decimal places), but multiplying that by 1,000,000,000,000 (which is 13 significant digits left of decimal point) means we are working with at least a combined 25 digits of significance. This far surpasses the 15 available for a double, so design-wise I think it would be very broken.
佚名

If GAAP Compliance is required or you need 4 decimal places:

DECIMAL(13, 4) Which supports a max value of:

$999,999,999.9999

Otherwise, if 2 decimal places is enough: DECIMAL(13,2)

src: https://rietta.com/blog/best-data-types-for-currencymoney-in/


s
shA.t

Indeed this relies on the programmer's preferences. I personally use: numeric(15,4) to conform to the Generally Accepted Accounting Principles (GAAP).


It has nothing whatsoever to do with "programmer's preferences" or what you 'personally use'. It is dictated by the problem domain, which requires a decimal radix. This is not a matter in which the programmer gets to exercise his own personal preferences.
D
Deepesh

Try using

Decimal(19,4)

this usually works with every other DB as well


d
digitalstraw

Storing money as BIGINT multiplied by 100 or more with the reason to use less storage space makes no sense in all "normal" situations.

To stay aligned with GAAP it is sufficient to store currencies in DECIMAL(13,4)

MySQL manual reads that it needs 4 bytes per 9 digits to store DECIMAL. https://dev.mysql.com/doc/refman/8.0/en/precision-math-decimal-characteristics.html

https://dev.mysql.com/doc/refman/8.0/en/precision-math-decimal-characteristics.html

DECIMAL(13,4) represents 9 digits + 4 fraction digits (decimal places) => 4 + 2 bytes = 6 bytes

compare to 8 bytes required to store BIGINT.


a
auntyellow

Multiplies 10000 and stores as BIGINT, like "Currency" in Visual Basic and Office. See https://msdn.microsoft.com/en-us/library/office/gg264338.aspx