简体   繁体   中英

Which one is the best database design for supporting multi-currency money values?

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:

Storing the monies

You should store the amount in one column, and the currency code in another.

Currency

You'll typically deal with ISO 4217 , which comes with 2 codes for each currency:

  • a 3-letter alpha code, such as EUR or USD
  • a 3-digit numeric code, such as 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.

Amount

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') .

Multiple amounts, single currency

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.

Retrieving the monies

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

Never ever store multiple values in the same column!!

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM