When talking of Database Normalisation, textbooks often talk of BCNF, fifth and higher normal forms. However, in practice (in large software/ERPs) I have rarely noticed normalisation beyond Third Normal form. In fact, there is a certain degree of redundancy that is desirable.
While doing database design, I believe there are two critical aspects that should be kept in mind but I see ignored in a lot of common software.
The first is the time aspect of data. First – an example from finance. Consider a company having multicurrency invoicing. The tables can be designed as:
INVOICE: InvoiceID, ..., Currency, BaseCurrency, TransactionDate, ...
CONVERSIONS: FromCurrency, ToCurrency, EffectiveDate, RateMultiplier
This is a design having no redundancy. On the basis of the three fields in the INVOICE
relation, we can always find out the latest row from the CONVERSIONS
table having EffectiveDate
less than TransactionDate
. Hence we can determine the RateMultiplier
.
Consider another design:
INVOICE: InvoiceID, …, Currency, BaseCurrency, TransactionDate, RateMultiplier, …
CONVERSIONS: FromCurrency, ToCurrency, EffectiveDate, RateMultiplier
Here, the system determines the value of the RateMultiplier
at the time of invoice creation and records it permanently within the INVOICE
table itself. To me this would be more mature design. Why? Because a lot of data in the INVOICE
table would actually depend on the RateMultiplier
: for example the VAT details. If on 1-JAN-2009 we know that the exchange rate is 1.1. However, on 3-JAN-2009 we come to know that the rate was incorrectly recorded. Someone changes the CONVERSIONS
table to reflect the new exchange rate, of 1.2. All the details in the INVOICE
table for the invoices created between 1-JAN and 3-JAN become inconsistent since the BaseCurrency
is now inconsistent with the RateMultiplier
.
Now consider an example from HR appraisal systems. A table stores what stage an appraisal process is at for a particular employee. This is then used to decide what access he has.
STAGE_CURRENT: EmpID, Stage
Note that this has no Date, or Year field. An employee is trying to see records for the previous year appraisals, yet is unable to see some of the data, because current appraisal process is still in initial stage.
The next problem is that of storage of “under calculation” fields. For example, consider the training department maintains the scores of each student trained. The test administered is of 100 marks, but has a weightage 40. Proposed design:
SCORES: CandidateID, TestID, Score, Flag
At the time of recording, the Flag
is set to N
. Thereafter a process runs that multiplies the score by 0.4 and sets the Flag
to Y
.
In my opinion a better design would be to retain both the scores even though the pre-weightage score is not relevant to the business process, because a process can also terminate in between due to erroneous data being supplied. Hence if the process ends after setting the flag to Y, and before changing the score; or in reverse order: after changing the score and before setting the flag then we end up with inconsistent data. Improved design:
Scores: CandidateID, TestID, Score, WeightedScore
At the time of recording, Score
is entered and WeightedScore
is set to zero. Thereafter a process runs that multiplies the Score
by 0.4 and stores the value in WeightedScore
.
The central idea is to retain all information permanently so that even if the process fails, we know what data existed.