Multi-Role Facts

Context: FIT3003_MOC · what to do when one transaction names the same dimension member in two roles · measure legality governed by Fact Measure Aggregation Rules Parent Framework: Star Schema Runnable script: 30_Projects/FIT3003_Labs/Lab03b_ROBCOR_clean_to_star.sql

Quick Revision

  • 🎯 Objective: one transaction, two participants of the same kind (pilot + co-pilot) ➔ build one star schema per role, not one star with two keys.
  • 📦 Core Components: charter_fact ➔ the pilot’s view | charter_fact2 ➔ the co-pilot’s view | identical dimensions, disjoint contents.
  • ⚠️ Key Constraint: the two facts may be union-merged only if the roles are disjoint per transaction. When both roles sit on the same trip, merging double-dips every measure that belongs to the trip rather than to the person.

📝 How It Works

1. The role-playing source

  • One table read twiceChar_Pilot and Char_CoPilot are both employee numbers drawn from PILOT; there is no second employee table.
  • The E/R diagram lies ➔ ROBCOR’s diagram shows a phantom Pilot_1 entity because the designer drew the two references as two boxes; the correct reading is one entity, two relationships.
  • Verify the roles before modelling ➔ probe that no record has the same employee as pilot and co-pilot, that no flight lacks a pilot, and that flights-with-copilot flights-without total ➔ Data Exploration (Warehouse Validation).

2. Why not one fact with two keys

  • A second key would change the grain ➔ adding CoPilot_ID to the composite PK makes the fact “per pilot pair”, and every co-pilotless flight then needs a dummy member.
  • The analysis question is per person“total hours flown by each pilot” ranges over employees, not over crews.

3. Two facts, then a scope test on merging

  • The merge is union inside an inline view, then re-aggregateunion alone leaves two rows per employee; the outer group by sums them.
  • Only individually-attributable measures survive ➔ flying hours are earned by a person; fuel and revenue are earned by the trip and are already recorded once by the other crew member.
  • Dropping the other dimensions is what makes the merge legal ➔ keep only the role dimension (Emp_Num); the moment Time_ID returns, the shared trip is counted twice inside one month.

4. The disjointness rule

  • Roles on the same transaction ⟹ overlap ➔ pilot and co-pilot fly the same trip, so their fact rows describe one event.
  • Roles across disjoint transactions ⟹ safe ➔ permanent vs sessional pilots (a trip has exactly one) can be union-ed with no re-aggregation at all: the two row sets never collide, and the result is simply both sets concatenated.

🗂️ Schema

  • CHARTER_FACT2 ➔ identical structure, Emp_Num populated from Char_CoPilot.
  • Dimensions · · — shared by both stars.
  • Revenue is computed, not stored, which forces AIRCRAFT and MODEL into the fact’s from clause purely to reach the per-mile rate.

⚙️ Core Implementation

🔹 The two role facts

🔹 Merging — the wrong one and the right one

⚖️ Merge Legality Matrix

MeasureAttributable toMerge across roles on Emp_NumMerge with Time_ID / Mod_Code retained
Tot_Char_Hoursthe person — each crew member logs their own hours✅ sum is the employee’s true total❌ the trip’s hours are also logged by the other crew member
Tot_Fuelthe trip — one tank, one flight❌ doubled whenever a flight has two crew❌ doubled
Revenuethe trip — one invoice, one flight❌ a \1000$2000$❌ doubled

When It Flips: the union becomes unconditionally safe — every measure, every dimension, no re-aggregation — the moment the two roles are mutually exclusive per transaction. Permanent vs sessional pilot passes; pilot vs co-pilot does not.

📊 Exam Execution Trace & Applied Exercises

Manual Execution Trace — employee 101

StepSourceValueVerdict
0dw.charter, Apr-1997101 appears as pilot and as co-pilot on one flightrole overlap confirmed
1charter_fact, Apr-1997, PA31-350 hrspilot-role view
2charter_fact2, Apr-1997, PA31-350 hrsco-pilot-role view
3charter_fact3, same keys hrs✓ correct as an employee total
4read step 3 as “April 1997 hours” hrs✗ the is also in the other pilot’s row
5charter_fact3b, Emp_Num only hrs✓ 101’s genuine lifetime hours
6same row, Tot_Fuel / Revenue gal · \447,900.57$✗ trips flown with a second crew member counted twice

Applied Exercise

Problem: one charter with a pilot and a co-pilot bills \1000100$ gallons. Compute what charter_fact3 reports versus the truth.

Final Extracted Output: Tot_Fuel and Revenue must be excluded from any cross-role merged fact; only Tot_Char_Hours survives, because hours are the sole quantity each crew member owns individually.

⚠️ Common Mistakes

  • 💡 Trusting the supplied E/R diagram ➔ ROBCOR’s phantom Pilot_1 entity has no table behind it; the diagram is a drawing convention for one entity used twice.
  • 💡 Modelling both roles as keys of one fact ➔ changes the grain to “per crew pair” and leaves solo flights needing a dummy co-pilot member.
  • 💡 union without re-aggregating ➔ union removes only identical rows; an employee appearing in both facts stays as two rows, and every roll-up over them is wrong ➔ SQL Set Operators.
  • 💡 Assuming a measure is additive because it is a sum ➔ additivity across fact rows is not additivity across roles; ask who owns the quantity ➔ Fact Measure Aggregation Rules.

🧠 Active Recall