Database Design – Understanding Fact Table Granularity

database-designdimensional-modelingfacttable

Myself and another DBA at our company are tasked with reviewing a database design that a vendor has developed for us. The vendor has said they use Kimball as the basis for their design. (NOTE: I am not looking for arguments of Kimball vs Inmon, etc.) They have designed a mart with multiple facts and dimensions.

Now in all fairness, our company has never designed a single mart. We have always had the consultants do it. And we have never been sent to classes or anything. So our knowledge of warehousing/marts/dimensional modelling, etc. is based on what little experience we have, what we can find on the Internet, and self reading (we have Inmon's and Kimball's books and are trying to make our way through them).

Now that the stage is set for my level of knowledge, we come to the design challenge.

There is a Fact table called "Claim Loss Statistics" (this is for insurance). And they are trying to capture both the payments for claims (rolled up to a monthly level), and then money in the reserves (kind of like a bank account for claims). They wish to see the monthly amounts for payments (no biggie). But they wish to see the account current balance of the reserves.

I'll give a pictorial example.

Say we set up $1000 USD in reserves for a claim. This gets set aside (so in some respects it functions kind of like a bank account).

In October 2014, we don't pay out anything yet. So the business wants to see the payments and the reserve balance at the end of October.

-----------------------------------------------
-  MONTH_YEAR  -  PAYMENTS -  RESERVE_BALANCE -
-----------------------------------------------
-      102014  -      0.00 -          1000.00 -
-----------------------------------------------

Then November comes along. We make out payments of $100, $150, and $75 dollars. They wish to see those amounts aggregated and the reserve at the balance as follows:

-----------------------------------------------
-  MONTH_YEAR  -  PAYMENTS -  RESERVE_BALANCE -
-----------------------------------------------
-      102014  -      0.00 -          1000.00 -
-----------------------------------------------
-      112014  -    325.00 -           675.00 -
-----------------------------------------------

And then say we have zero payments in December and then $200 more in January next year.

-----------------------------------------------
-  MONTH_YEAR  -  PAYMENTS -  RESERVE_BALANCE -
-----------------------------------------------
-      102014  -      0.00 -          1000.00 -
-----------------------------------------------
-      112014  -    325.00 -           675.00 -
-----------------------------------------------
-      122014  -      0.00 -           675.00 -
-----------------------------------------------
-       12015  -    200.00 -           475.00 -
-----------------------------------------------

Here is where I struggle. My understanding is that the payments part is correct. They are all rolled up at a monthly level within each record. So you can rollup further if you want for the year, quarter, etc.

But the reserves amount is different. It is a balance. And the business wants to see how much is in the balance at each month. But you can't aggregate on this field. If you did, you would get some wonky results.

Somehow this strikes me as wrong. But I can't truthfully say I've modelled enough or know enough. All I can say is what I know. And from what I know, all values in a Fact should be at the same granularity.

Both numbers are at the same granularity of a "month", but they are not from the standpoint of what they stand for. One is aggregate dollars within a month. The other is just the balance.

Is this correct? I have been pushing back on this design. Am I wrong to do so? Is it ok to do this in a Fact? Or is my sense of "code smell" of a bad design accurate?

Any help would be appreciated. NOTE: please don't just say "It should be way X", please explain why it should be that way so I can learn from this.

EDIT: Well, I learned that my initial understanding of the Fact is wrong. The granularity is NOT monthly. The granularity is
transaction level. So that means within the MONTH_YEAR (ie really it
is the financial reporting period) there will be multiple payment and
recovery transactions. Those will be posted by date or transaction
date. But because of a prior report the business sees, and also
because of how the data is stored in the legacy system that this comes
from they wanted to put both the transactional data (one row per) and
the reserve monthly balance (one row per month).

Once I learned that, I realize the problem was not so much additive vs
non-additive, or even semi-additive as it was grain, which is what I
was suspecting from the start. Our DBA team discussed this with the
project team and reported that they are attempting to put two
different grains in the same fact, and this was not correct. That they
should either role up the transactions to a monthly level, allowing
them to then have the payments, recoveries, and the monthly reserve
balance (ie a semi-additive fact) because everything would be at a
monthly grain. Or they need to find a way to break down the reserve
balance into transactions to preserve the transaction level grain. Or
they need to break the fact into two facts. One can be the monthly
level for the reserve balance. The other can be at the transaction
level for the payments and recoveries. (There is no reason why they
also couldn't put the payments and recoveries at a monthly level in
the monthly level fact too. Just depends on the business needs.)

Given what I have learned, I will be marking Thomas' answer as the
correct one. However, I feel the discussion I started with the
original question is still a good one for others to learn from, so I
will leave the original portion of my question intact. I also intend
to award a bounty to nikadam's answer as that taught me a lot about
additive, non-additive, and semi-additive facts, and corrected a lot
of misunderstandings I had about dimensional modelling.

Best Answer

Your intuition of code smell is well honed.

What you are dealing with on reserves is what Kimball calls a "semi-additive fact". It does not roll up nicely to quarter or year.

The typical solution to this is to have two fact tables, one for the additive fact (payments in your case) and one for the non-additive fact. The non-additive fact does not actually need to have a grain at the month level, you could store them all the way to the day and things still just work.

The non-additive fact, reserve, is queried differently than the other fact. There is a business decision you need to make: What does reserve at the year level mean? Is it the last month of the year, or maybe the average of the months in the year? Whichever choice you make, you can find the solution to modeling this it in the Kimball books under the chapters on non-additive facts.

Please note that if you use a cube product like Analysis Services, it is possible to have the aggregates "just work" even if you store it all in one table. However, I prefer to keep things separate so relational queries are easier to write (and the facts are easier to load too).