I want to know the best database design for storing multi-currency money values in database. For example I have one Entity that has two money fields. These fields may have different currency types for each record.
Example:
Table A:
-------------
Id
Name
Amount1
Amount2
Sample records:
Id Name Amount1 Amount2
1 aaa 12$ 15£
2 bbb 30€ 17$
I cannot store values in one currency. For example I want to lend somebody money. I store its data in a table. The type of money can be different. When I lend someone 10€ I should take back 10€ and I cannot store all values in one currency like dollar.
I want to know what the best and more efficient design for storing these values in database is. Should I store amount and currency sign in one column with string data type or it is better to define Money
and Currency
tables as separate tables for storing money values? Or any other design?
Without commenting too much on the actual structure of your table (2 or more monies in a single table is OK, as long as they have business meaning—like subtotal
, shippingFee
and total
), I'll focus on how to store them:
You should store the amount in one column, and the currency code in another.
You'll typically deal with ISO 4217 , which comes with 2 codes for each currency:
EUR
or USD
978
or 840
Which one you use is up to you. You can save one byte per record by using numeric codes. On the other hand, alpha codes are easier to read and remember for humans, and could make it easier to use custom currencies (crypto), that may have a de-facto standard alpha code but no numeric code.
Because currencies may have different numbers of decimal places (2 for EUR
, USD
etc., but 0 for JPY
, 3 for TND
...), I always advise to store amounts in minor currency units (cents) as an integer.
Your table would therefore look like:
amount INT NOT NULL,
currencyCode CHAR(3) NOT NULL
If you want to store 12.34 USD
, you'll actually store (1234, 'USD')
.
If your table holds several monies that will always be in a single currency (like the subtotal
/ shippingFee
/ total
example above), all 3 amounts can share a single currency code:
subtotal INT NOT NULL,
shippingFee INT NOT NULL,
total INT NOT NULL,
currencyCode CHAR(3) NOT NULL
In this case, you probably don't need separate subtotalCurrencyCode
, shippingFeeCurrencyCode
and totalCurrencyCode
, although there are other business cases where amounts will be in different currencies. The decision is yours.
Of course dealing with integer amounts is not very easy, so you'll need to use a money library that supports converting from/to minor amounts.
For example in PHP, you can use brick/money (disclaimer: I'm the author):
$money = Money::ofMinor(1234, 'USD');
$money->getAmount(); // 12.34
$money->getMinorAmount(); // 1234
The currecny and the amount need to be separated. Also, if you have column names with numbers then you most probably do something wrong. This is one way to do it:
table products
--------------
id
name
table prices
------------
id
product_id
amount
currency_id
table currencies
----------------
id
name
abbreviation_sign
Then to get the Dollar price of a product you can do
select pri.amount
from prices pri
join products prod on prod.id = pri.product_id
join currencies c on c.id = pri.currency_id
where prod.id = 123
and c.name = 'Dollar'
With proper indexes this is really fast to query.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.