Fact Measure Aggregation Rules

Context: FIT3003_MOC Β· which aggregate may legally become a stored measure in Building Fact Tables Parent Framework: Star Schema

Quick Revision

  • 🎯 Objective: a stored measure must survive re-aggregation βž” the analyst re-sums fact rows to roll up, so only measures whose roll-up equals the operational answer may be stored.
  • πŸ“¦ Core Components: count/sum βž” always safe | min/max βž” safe but not mixable | avg βž” never store.
  • ⚑ Key Constraint: an average of averages is not the average β€” replace Average_X with Total_X and Number_of_Y, and divide at query time.

πŸ“ How It Works

1. Count semantics β€” pick the right one

  • count(*) βž” number of records in the group, NULLs included.
  • count(attribute) βž” excludes NULL values β€” the measure that makes an outer-joined fact correct.
  • count(distinct attribute) βž” removes duplication; Total Apps needs count(distinct ApplicationID) because one application appears once per download row.

2. Sum

  • Always re-aggregable βž” of group sums the global sum, so a stored sum rolls up correctly to any coarser grain.
  • Count and Sum are the common measures βž” the chapter’s default expectation for a fact table.

3. Average β€” the trap

  • Roll-up breaks βž” of per-group averages ignores group sizes, so it equals the true average only when all groups are the same size.
  • Correction is decomposition βž” store and ; recover the average with sum(Total_Score)/sum(Number_of_Students).

4. Min / Max

  • Global value guaranteed βž” of group maxima the global maximum, likewise ; both may be stored.
  • Never mix them βž” max(Min_Score) or min(Max_Score) is a meaningless quantity.

βš™οΈ Core Implementation

πŸ”Ή Average of an average β€” the failing fact vs its correction

πŸ”Ή Min / Max stored safely

βš–οΈ Core Decision Matrix

AggregateStored as a measure?Roll-up behaviourRecovery at query time
count(*) / count(col) / count(distinct col)βœ…additivesum() over fact rows
sumβœ…additivesum() over fact rows
min / maxβœ… (separately)semi-additive β€” global value survivesmin() / max(), never crossed
avg❌not additive β€” weights are loststore total + count, then sum/sum

When It Flips: an average is safe to display and unsafe to store. The rule fires the moment a fact row can be combined with another fact row β€” which is always, because that is what a dimension roll-up does.

πŸ“Š Exam Execution Trace & Applied Exercises

Manual Execution Trace β€” IT001 β€œDatabase”, two semesters

StepSourceValueRunning interpretation
0operational rows, sem 1 scores summing to true group total
1operational rows, sem 2 scores summing to true group total
2fact v1 stores averages, sizes discarded
3roll up fact v1βœ— wrong by
4roll up fact v2βœ“

Applied Exercise

Problem: the FitnessCentreFACT stores Num_of_Employees and Total_Salary by JobTitle, Month, EmploymentType, Gender. Why not Average_Salary?

Final Extracted Output: Total_Salary + Num_of_Employees is strictly more informative than Average_Salary β€” the average is recoverable from them, they are not recoverable from it.

🧠 Active Recall