views:

329

answers:

4

I need a table to store the state of a financial transaction. The state of this transaction can be roughly modelled by this class.

class FinancialTransaction
{
    Integer txId,
    Money oldLimit,
    Money newLimit,
    Money oldBalance,
    Money newBalance,
    Date txDate
}
class Money
{   
    Currency curr,
    BigDecimal amount
}

My initial design of the schema looks like this:

CREATE TABLE tx
(
    txId bigint(20) unsigned NOT NULL,
    oldlimit_currency varchar(3) NULL,
    oldlimit_amount decimal(7,5) default 0.00,
    newlimit_currency varchar(3) NULL,
    newlimit_amount decimal(7,5) default 0.00,
    ----snipped----
    PRIMARY KEY (txId)
)

Two things worry me:

  1. Each transaction occurs based on one Currency. I haven't thought far enough as to whether I might need to support transactions that may happen in multiple currencies. Assuming that it doesn't change; then isn't it more space-efficient to just maintain one currency column ? Will I regret this simplistic solution ?
  2. Since each Money item is a value object, should I instead save all Money objects into a separate Money table and have the original table use moneyIds as foreign keys to the Money table ?

That is,

CREATE TABLE tx
(
    txId bigint(20) unsigned NOT NULL,
    oldlimit_money_id int NOT NULL,
    newlimit_money_id int NOT NULL,
    ----snipped----
    PRIMARY KEY (txId),
    FOREIGN KEY (oldlimit_money_id) REFERENCES MONEY(id) ON DELETE NO ACTION ON UPDATE NO ACTION,
    FOREIGN KEY (newlimit_money_id) REFERENCES MONEY(id) ON DELETE NO ACTION ON UPDATE NO ACTION
)

Are there alternative designs ?

Thanks lazyweb.

+2  A: 
  1. If in future you do need to support transactions between two currencies, it ought to be possible to model this as two transactions with one of each currency.
  2. It looks like your Money objects are, semantically, values rather than entities. Thus I don't see the need to separate them out as entities.
MandyK
+3  A: 

The currency and money value are two different concepts so would be better to separate them. There is no need to make a separate table for 'values' but would be better to have one for currencies because these are separate entities. The new design would look like:

CREATE TABLE tx
(
    id bigint(20) unsigned primary key,
    old_limit_currency_id int not null references CURRENCY(id),
    old_limit_value decimal(7,5) not null,
    new_limit_currency_id int not null references CURRENCY(id),
    new_limit_value decimal(7,5) not null
)

Also, check if decimal(7,5) has enough space for your scenarios, it looks a little low. There is an old saying: "Better safe than sorry" :)

Aleris
And thanks for pointing out that gotcha about the decimal(7,5). I will certainly review that with the DBA.
ashitaka
A: 

If it's not an overkill, go one step further and store all amounts/values in a single currency and maintain an exchange rates table.

Rahul
you would need to maintain whole rate history to perform valid calculations that refer transactions in the past
miceuz
+2  A: 

What about a third idea:

CREATE TABLE tx
(
  txId bigint(20) unsigned NOT NULL,
  currency varchar(3) NOT NULL,
  oldlimit decimal(7,5) default 0.00,
  newlimit decimal(7,5) default 0.00,
  ----snipped----
  PRIMARY KEY (txId)
)

All money values of one transaction need to be of the same currency, right?

Arne Burmeister
That's a nice optimization that I might consider. Thanks
ashitaka