I am using approach, where each object that I'm dealing with has at least 1 so called instance table, where I keep the data that tends to change over time. Typically such tables follow the following concept:
- they have
_HISTORY
suffix in the name;
- they have 2 extra fields,
start_dt
and end_dt
, indicating object instance's lifetime;
start_dt
is NOT NULL
, end_dt
can be NULL
, which indicates that instance is current and is not limited in it's time;
- it is possible to insert future-dated changes, say you want a new company name to be activated from
1/Jan-2013
, then you need to set end_dt
of the current instance to 31/Dec-2012 23:59:59
and insert a new record with start_dt
of 1/Jan-2013 00:00:00
;
- sometimes I also add
revision
field, if it is necessary to track revisions.
In order to have a proper RI constraints with such design, I always have 2 tables for versioned obejcts. Say, for Customer
obejct I have the following set of tables:
customer (customer_id INTEGER, PRIMARY KEY (customer_id));
customer_history (customer_id INTEGER, start_dt TIMESTAMP, end_dt TIMESTAMP,
name VARCHAR(50), sex CHAR(1), ...,
PRIMARY KEY (customer_id, start_dt));
customer_bank_history (customer_id INTEGER, start_dt TIMESTAMP, end_dt TIMESTAMP,
bank_id INTEGER, iban VARCHAR(34));
In all other places I use customer(customer_id)
to build foreign keys. Querying actual customer details is simple:
SELECT c.customer_id, ch.name, ch.sex
FROM customer c
JOIN customer_history ch ON c.customer_id = ch.customer_id
AND now() BETWEEN ch.start_dt AND coalesce(end_dt, now());
Why I prefer such design:
- I have versioned object instances on the database level by design;
- I have to maintain less tables;
- It is not possible to get history lost in case somebody drops/disables any triggers;
- I can plan and maintain future-dated changes easily.
Hope this will help you.