Data modeling defined flat: the three model levels, entities and cardinality, candidate and composite keys, factless facts, galaxy schemas, natural against business against surrogate keys, SCD 4 and 6, the bus matrix, outriggers, allocation factors, BCNF and 4NF, Data Vault parts, late-arriving dimensions, ragged hierarchies, the date dimension, data marts, corrections to facts, Type 2 validity columns, many-to-many resolution and reference data, plus the ten one-liners every warehouse screen opens with.
The three model levels, entities and cardinality, the key vocabulary, and the normal forms past 3NF.
Dimensional vocabulary
8
Factless facts, galaxy schemas, the bus matrix, outriggers, allocation factors, the date dimension, hierarchies and marts.
History & change
3
SCD Types 4 and 6, the validity columns on a Type 2 row, and how corrections to facts land.
Vault, bridges & reference data
4
Hubs, links and satellites, how a many-to-many is resolved, what a lookup table is for, and the late-arriving dimension.
Evergreen · asked verbatim
10
The flat form, in the words interviewers use. The one-line definitions every warehouse screen opens with.
01 / 30
Kimball vs Inmon vs Data VaultNormalization forms
What are the conceptual, logical and physical levels of a data model? What does each one decide, and who reads it?
Why they ask this
It shows whether you separate what the business means from how a database stores it, which is the whole discipline.
Say this
A conceptual model names the business entities and how they relate, with no attributes or keys: Customer places Order. A logical model adds attributes, keys and cardinality, independent of any database. A physical model maps that to one engine: tables, column types, indexes, partitions and constraints. Each level is read by a different audience and changes at a different speed.
The reasoning
The conceptual level is the business vocabulary. It lists entities such as Customer, Order and Product and the relationships between them, and nothing else. A product owner can read it and say "yes, that is our business" or "no, a subscription is not an order".
The logical level adds the detail a designer needs: every attribute, the primary key of each entity, the foreign keys, and the cardinality of each relationship. It is still engine-neutral. The same logical model can become PostgreSQL tables or a Snowflake star schema.
The physical level is the DDL. It chooses column types, surrogate keys, indexes or clustering, partitioning, and whether a relationship becomes a foreign key constraint or a test. It is the only level the database sees.
The separation matters because the levels change at different speeds. The conceptual model changes when the business changes. The physical model changes when you move from Redshift to BigQuery. Mixing them means a storage decision rewrites the business vocabulary.
The answer most people give
"The logical model is the ERD and the physical model is the same thing with data types." The logical model is already keyed and attributed. The physical model also decides partitioning, indexes, denormalization and the surrogate key strategy, which the logical model never mentions.
They’ll ask next
A team moves a warehouse from Redshift to BigQuery. Which of the three levels should change, and which should not?
What are entities, attributes and relationships in an entity-relationship model? What are the cardinality types, and why does cardinality matter?
Why they ask this
Cardinality is the first thing an interviewer checks when you sketch a model, because fan-out bugs start there.
Say this
An entity is a thing the business tracks, such as Customer. An attribute is a fact about it, such as email. A relationship links entities, and its cardinality says how many of each side can take part: one-to-one, one-to-many, many-to-many. Cardinality decides where the foreign key goes and whether a join can multiply rows.
The reasoning
An entity becomes a table; an attribute becomes a column; a relationship becomes a foreign key or a bridge table. The modeler's first job is to name the entities so that each one has a single, clear identity.
One-to-many is the common case: one customer, many orders. The foreign key goes on the many side, `orders.customer_id`. One-to-one is rare and usually a sign that two tables could be one, or that one side is optional and kept apart on purpose.
Many-to-many cannot be stored with a single foreign key. One student takes many courses, one course has many students. It needs a third table with both keys, an enrolment or bridge table, which is where the relationship's own attributes live, such as the enrolment date.
Cardinality matters because it predicts join behaviour. Joining a fact to a dimension on a one-to-many key keeps the fact's row count. Joining through a many-to-many without a bridge duplicates rows and inflates every sum. Optionality, whether a side can have zero, decides inner against left join.
The answer most people give
"Cardinality is just a diagram notation." It is the rule that decides which table holds the key, whether a bridge is needed, and whether a sum survives a join. Get it wrong and revenue doubles.
They’ll ask next
Orders join to a shipments table and total revenue rises by 30 percent. Which cardinality assumption broke, and what does it tell you about shipments?
What is a primary key, a candidate key and a composite key? How do they differ from a superkey?
Why they ask this
Key vocabulary is the base of normalization and of every uniqueness test a pipeline runs.
Say this
A superkey is any set of columns that is unique for every row. A candidate key is a minimal superkey: remove any column and it stops being unique. The primary key is the one candidate key you choose to identify rows. A composite key is any key made of more than one column, such as (order_id, line_number).
The reasoning
Uniqueness is the property; the key terms describe how tight the set is. (customer_id, email) is a superkey if customer_id alone is unique, but it is not a candidate key, because email is unnecessary.
A table can have several candidate keys. An employee table may have employee_id and national_id, both unique. You pick one as the primary key and the others become alternate keys, often enforced with a unique constraint.
A composite key is a key with more than one column. Fact tables often have a composite natural key: (date_key, store_key, product_key) for a daily snapshot. Order lines are (order_id, line_number). Composite keys are correct and common; the choice is whether to also add a single surrogate column for convenience.
In a pipeline these terms become tests. The primary key is asserted unique and not null after every load. A duplicate on the primary key means the load ran twice or the grain was misunderstood. A candidate key that stops being unique, such as a reused email, is a business finding worth raising.
The answer most people give
"A composite key is a bad design; every table should have a single integer key." A composite natural key is often the correct grain statement. A surrogate may be added for joins, but the composite key is still what uniqueness tests should check.
They’ll ask next
A daily inventory snapshot has the key (date_key, sku_key, warehouse_key). A load inserts the same day twice. Which test catches it, and what does the fix look like?
What are Boyce-Codd normal form and fourth normal form? What anomaly does each one remove that third normal form leaves behind?
Why they ask this
Everyone can recite 1NF to 3NF; the step past it shows you understand dependencies rather than a checklist.
Say this
BCNF requires that for every non-trivial functional dependency X determines Y, X is a superkey. It closes the 3NF loophole where a non-key column determines part of a key. 4NF goes further: it removes multi-valued dependencies, where two independent repeating facts about the same key are stored in one table and multiply each other. Both are fixed by splitting the table.
The reasoning
Third normal form allows one odd case: a dependency where a non-key attribute determines a key attribute. The classic example is (student, course, instructor) where each instructor teaches one course. Instructor determines course, but instructor is not a key. Updates to an instructor's course can go inconsistent.
BCNF forbids that case. Every determinant must be a superkey. The fix is to split into (instructor, course) and (student, instructor). Most tables in 3NF are already in BCNF; the difference appears only with overlapping candidate keys.
4NF addresses a different problem. Suppose an employee has several skills and several languages, and they are independent. A table (employee, skill, language) must hold every skill paired with every language, so adding one language adds a row per skill. That is a multi-valued dependency. 4NF says split into (employee, skill) and (employee, language).
In warehouse work the practical echo is the many-to-many bridge. Two independent multi-valued attributes on one dimension row, say a patient's diagnoses and medications, must each get their own bridge. Putting both in one bridge multiplies rows exactly as the 4NF example does.
The answer most people give
"BCNF and 3NF are the same thing in practice." Usually they coincide, but the case where they differ, a non-key determinant of a key column, is a real update anomaly. 4NF is about independent repeating groups, which is a different failure.
They’ll ask next
A dimension row for a product carries both a list of colours and a list of sizes in one bridge table. Which normal form is violated, and how do you fix it in a star schema?
What is the difference between a natural key, a business key and a surrogate key? Why do dimensions get a surrogate key even when the business key is unique?
Why they ask this
The surrogate key is what makes SCD Type 2 possible, and candidates often cannot say why.
Say this
A natural key is a real-world identifier that exists in the data, such as an ISBN. A business key is the identifier the business uses to recognise the thing, such as a customer number; it is often the natural key, but it may be assigned by a source system. A surrogate key is a meaningless integer or hash the warehouse generates. Dimensions get one so that a single business key can have several rows over time.
The reasoning
The terms overlap, and the useful distinction is who assigns them. A natural key comes from the world: an ISBN, a VAT number. A business key comes from the operating system of record: customer number 10045. A surrogate key comes from the warehouse load and means nothing outside it.
Kimball's rule is that every dimension gets a surrogate key and facts reference it, not the business key. The reason is history. Under SCD Type 2, customer 10045 may have three rows, one per address version. The business key is no longer unique in the dimension, so the fact needs another column to point at one version.
Surrogates also insulate the warehouse from source changes. Business keys get reused, reformatted, or collide when two source systems merge. A surrogate stays stable. It also lets you add special rows, such as key 0 for "unknown", that no source produced.
The costs are a lookup on every fact load to translate business key to the current surrogate, and a key that users cannot read. Data Vault 2.0 instead hashes the business key, which removes the lookup but keeps the business key as the identity.
The answer most people give
"A surrogate key is just for performance because integers join faster." Join speed is minor. The reason is that Type 2 history breaks business key uniqueness, and the surrogate is what identifies one version of a member.
They’ll ask next
Two acquired companies both have a customer number 10045. Which key type resolves the collision in the warehouse, and what does the fact table reference?
What is a factless fact table? What are its two uses, and how do you count with it?
Why they ask this
It tests whether you know a fact table records an event, not a number.
Say this
A factless fact table records that an event or a relationship happened but carries no numeric measure, only foreign keys. Kimball names two uses: recording events, such as a student attending a class on a date, and recording coverage, such as which products were on promotion in which store that week. You count by counting rows or with a constant 1 column.
The reasoning
A normal fact row says "this happened, and here is how much". A factless row says only "this happened". A row in attendance holds (date_key, student_key, class_key) and nothing else. The question "how many students attended class 7 on Monday" is `COUNT(*)` with two filters.
The second use is coverage. A promotion coverage table records every (week, store, product) that was on promotion. Alone it answers "what was promoted". Joined against sales, it answers "what was promoted but did not sell", the question the sales fact cannot answer because non-sales have no row.
Many designers add a column `count` that is always 1. It costs nothing and lets BI tools sum a measure instead of counting rows, which some tools handle better.
The grain statement is still required. "One row per student per class per date" is a grain. Without it, duplicates from a double load are invisible, because there is no measure to look wrong.
The answer most people give
"A factless fact table is a dimension." It is a fact table at a stated grain with foreign keys to several dimensions. A dimension describes one thing; a factless fact records an intersection of several.
They’ll ask next
Marketing asks which promoted products had zero sales last week. Which two tables do you need, and what join type returns the answer?
Star vs snowflakeDimension types (conformed, degenerate, junk, role-playing, bridge)
What is a galaxy schema, also called a fact constellation? How does it differ from a star and a snowflake, and what makes it work?
Why they ask this
Most candidates stop at star against snowflake; the galaxy term checks whether you know what shared dimensions buy you.
Say this
A galaxy schema is several fact tables that share dimensions. Sales and inventory facts both join to the same product, store and date dimensions. A star is one fact with its dimensions; a snowflake normalises those dimensions into sub-tables. A galaxy is the normal shape of a real warehouse, and it works only when the shared dimensions are conformed, meaning identical in keys and attributes.
The reasoning
The star is the unit: one fact table in the middle, one join away from each dimension. A real business has many processes, so it has many facts: orders, shipments, returns, inventory. Drawn together they look like constellations, which is where the name comes from.
The value is in the shared dimensions. If sales and inventory both use the same product dimension with the same surrogate keys, a report can show sales and stock side by side per product. That is drill-across, and it is the point of a warehouse rather than a pile of reports.
The condition is conformance. Two product dimensions with different keys or different category names cannot be compared. Kimball's bus matrix is the planning tool: rows are business processes, columns are dimensions, and a tick means the process uses that conformed dimension.
Snowflaking is orthogonal. Any fact in a galaxy may have snowflaked dimensions; the galaxy term describes how facts relate to each other, not how a dimension is normalised.
The answer most people give
"A galaxy schema is a snowflake with more tables." Snowflake describes a normalised dimension. Galaxy describes several facts sharing dimensions. A galaxy of pure stars is common.
They’ll ask next
Sales uses product_key from one load and inventory uses product_key from another. Reports disagree on category totals. Which property of the galaxy failed?
Kimball vs Inmon vs Data VaultDimension types (conformed, degenerate, junk, role-playing, bridge)
What is a bus matrix in dimensional modeling? What goes on its rows and columns, and what decisions does it drive?
Why they ask this
It separates people who have planned a warehouse from people who have built one table.
Say this
The bus matrix is Kimball's planning grid. Rows are business processes, each becoming a fact table: orders, shipments, payments. Columns are dimensions: date, customer, product, store. A mark says the process uses that dimension. It shows which dimensions must be conformed because several processes share them, and which process to build first.
The reasoning
The matrix is built before any table. You list the processes the business runs and the dimensions it describes them with. A process that touches customer, product and date gets three marks. Reading down a column shows every process that needs that dimension.
A column with many marks is a conformed dimension by necessity. Customer appears in orders, support tickets and payments, so one customer dimension must serve all three. Building it once and well is the highest-leverage work in the warehouse.
Reading across a row shows the scope of one fact table. The first fact to build is the one the business values most that touches dimensions you can conform quickly. That is how a warehouse gets delivered in increments without becoming three incompatible marts.
The matrix is also the document you keep. When a new process arrives, you add a row and see which dimensions already exist. When someone proposes a second customer table, the column shows the damage.
The answer most people give
"The bus matrix is an ERD of the warehouse." It has no keys, no attributes and no cardinality. It is a grid of processes against dimensions used to plan conformance and delivery order.
They’ll ask next
Three teams each want their own customer dimension. Which cell of the matrix do you show them, and what do you require instead?
Star vs snowflakeDimension types (conformed, degenerate, junk, role-playing, bridge)
What is an outrigger dimension? When is it acceptable, and why is it usually a mistake?
Why they ask this
It checks whether you can resist normalising a dimension, which is the habit relational modelers bring to a star schema.
Say this
An outrigger is a dimension table hanging off another dimension rather than off the fact. A customer dimension with a foreign key to a separate demographics or date table has an outrigger. Kimball allows it for a date attribute on a dimension, such as customer first-purchase date pointing at the date dimension, and for a large, rarely used block of attributes. As a general pattern it is a snowflake and costs an extra join on every query.
The reasoning
The star schema rule is that dimensions are flat and denormalised. If a customer's country has a region and a region has a manager, all three live as columns on the customer row. An outrigger breaks that rule by moving some attributes to a second table reached through the dimension.
The acceptable case is a date on a dimension. First purchase date, hire date, contract start. Pointing it at the date dimension gives every calendar attribute for free, fiscal period, holiday flag, without copying them onto the dimension. Kimball's own guidance names this as the common legitimate outrigger.
The other acceptable case is a large block of low-cardinality attributes that few queries use, where keeping them on the main row bloats it. Even then, many teams prefer a mini-dimension joined from the fact instead, which is SCD Type 4.
The cost is a two-hop join and BI tools that expect dimensions one join from the fact. The usual failure is a modeler building outriggers everywhere because the source system was normalised. The fix is to flatten at load time.
The answer most people give
"An outrigger is a bridge table." A bridge resolves a many-to-many between a fact and a dimension. An outrigger is a one-to-many lookup off a dimension, a snowflake arm.
They’ll ask next
A customer dimension points at a country table, which points at a region table. How many joins does a sales-by-region report need, and what does flattening change?
What is an allocation factor, also called a weighting factor, on a bridge table? What problem does it solve, and what must its values satisfy?
Why they ask this
It is the detail that separates a bridge that doubles revenue from one that reports it correctly.
Say this
A bridge between a fact and a multi-valued dimension, such as an account with several owners, multiplies fact rows when joined. An allocation factor is a column on the bridge, one value per member, that sums to 1 within each group. Multiplying the measure by the factor spreads the amount across members so the total is unchanged. Kimball calls this a weighted report; omitting the factor gives an impact report.
The reasoning
An account with two owners has two bridge rows. Joining a balance fact through the bridge returns the balance twice. Summing gives double the money. That is the many-to-many fan-out, and it is the reason bridges are feared.
The allocation factor fixes the sum. With factors 0.5 and 0.5, each owner is credited half the balance and the total is correct. With 0.7 and 0.3 the business decides who gets more. The constraint is that factors within one group sum to exactly 1.
Both reports are valid. "How much money is attributable to each owner" is the weighted report and uses the factor. "How much money is each owner connected to" is the impact report and ignores the factor on purpose, accepting that it does not add to the total.
Floating-point factors that sum to 0.9999 leak money. Store them as decimals, test the sum per group, and decide the rounding rule for a 3-owner account before the first load.
The answer most people give
"You fix the fan-out by taking the first owner." That hides the relationship and reports every account under one owner. The factor keeps every member and keeps the total.
They’ll ask next
A patient visit has three diagnoses. Finance wants cost per diagnosis to add up to the visit cost. What goes on the bridge, and what test guards it?
What is a date dimension, and why do warehouses use one instead of a plain date column on the fact? What belongs in it?
Why they ask this
It is the most common dimension in any warehouse, and the reasons for it are a quick test of dimensional thinking.
Say this
A date dimension is a table with one row per calendar day and columns for every attribute of that day: year, quarter, month, day of week, fiscal period, holiday flag, week start. The fact stores a date key pointing at it. It exists because calendar logic, especially fiscal calendars and holidays, cannot be computed from a date, and because it makes those attributes conformed across every fact.
The reasoning
Some date attributes are computable: year, month, weekday. Many are not: the fiscal quarter when the fiscal year starts in April, whether a day is a trading day, which marketing week it falls in. A table holds them once, and every query reads them with a join rather than reimplementing them.
The key is usually an integer like 20261101, readable and sortable, or the date itself in engines that partition by date. Kimball recommends a surrogate but notes the date case is the one where a meaningful key is acceptable.
The table is small, a few thousand rows for a decade, and is generated by a script, not loaded from a source. Columns typically include the day, week, month, quarter, year, their fiscal equivalents, day-of-week name, a weekend flag, a holiday flag per country, and relative markers such as is_current_month.
It also plays roles. The same table joins as order_date, ship_date and delivery_date through three foreign keys, a role-playing dimension. Time of day is usually a separate time dimension or a plain timestamp, because a row per second is too many.
The answer most people give
"You do not need it; `EXTRACT(month FROM date)` does the same thing." It does not know your fiscal calendar, your holidays or your reporting weeks, and every analyst reimplements them differently.
They’ll ask next
The company's fiscal year starts on 1 February. Where does that rule live so that every dashboard agrees, and how is it loaded?
What is a hierarchy in a dimension, and what makes one ragged? How do you store a ragged hierarchy for drill-down?
Why they ask this
Drill-down is what dashboards do all day, and organisation charts are never balanced.
Say this
A hierarchy is a set of attributes with a fixed order of levels: country, region, city. A balanced hierarchy has every leaf at the same depth, so the levels become columns on the dimension. A ragged hierarchy has leaves at different depths, such as an org chart where some managers have no reports. It is stored either as a parent-key self-reference walked by a recursive query, or as a bridge table that lists every ancestor-descendant pair.
The reasoning
The fixed-depth case is easy. Product has category and department, so the dimension row carries all three columns, and drill-down is a `GROUP BY` on a different column. This is the denormalised star pattern and it works because the depth never varies.
Ragged means the depth varies. One employee is four levels below the CEO, another is two. You cannot make level_3 a column, because for some rows it is empty and for others it is a leaf. Geography is often ragged too: a city-state has no region.
Option one is a parent pointer: each row carries its parent's key. Querying "everyone under manager X" needs a recursive CTE, which BI tools handle poorly. Option two, Kimball's hierarchy bridge, stores one row per (ancestor, descendant, depth) pair, including each node with itself. Then "everyone under X" is a simple join to ancestor = X.
The bridge is larger, roughly nodes times average depth, and must be rebuilt when the tree changes. Some teams fix the depth instead by padding: repeating the leaf value down to the deepest level so every row has all columns. That trades truth for speed and must be documented.
The answer most people give
"Store the hierarchy as level_1, level_2, level_3 columns." That works only when every leaf has the same depth. A ragged tree leaves holes, and totals at a level miss the nodes that sit above or below it.
They’ll ask next
A dashboard must show revenue for a manager and every team under them, to any depth. Which storage option do you choose, and what rebuilds it when someone changes team?
Kimball vs Inmon vs Data VaultMedallion / lakehouse layers
What is a data mart? How does a dependent mart differ from an independent one, and how do Kimball and Inmon use the term?
Why they ask this
The word is used loosely in every company, and the interviewer wants to hear which meaning you intend.
Say this
A data mart is a subject-area slice of warehouse data shaped for one audience: a finance mart, a marketing mart. A dependent mart is built from the enterprise warehouse and shares its conformed dimensions. An independent mart is loaded straight from sources with its own definitions. Inmon's architecture makes marts dependent on a normalised warehouse; Kimball's marts are the star schemas themselves, tied together by the bus.
The reasoning
In Inmon's design the enterprise data warehouse is a normalised, integrated store, and marts are downstream, dimensional, and built per department from it. The warehouse is the single source; a mart is a view into it.
In Kimball's design there is no separate normalised layer. The marts are the dimensional models, and the conformed dimensions on the bus are what make them one warehouse. A mart is a group of fact tables for one process area.
The dangerous kind is the independent mart. Marketing loads customers from the CRM with its own rules, finance loads them from billing. The two marts disagree on customer count and neither is wrong by its own definition. That disagreement is what conformance exists to prevent.
In modern warehouses a mart is often a schema of final models in dbt, built from a shared core layer. The vocabulary is Inmon-shaped even where the core is dimensional: shared layer first, audience-specific marts after.
The answer most people give
"A data mart is a small data warehouse." Size is not the distinction. A mart is scoped to a subject or audience, and whether it is dependent on a shared layer decides whether its numbers agree with everyone else's.
They’ll ask next
Finance and marketing marts report different active-customer counts. Which kind of mart are they, and what layer would make them agree?
What are slowly changing dimension Types 4 and 6? What problem does each solve that Types 1, 2 and 3 do not?
Why they ask this
Types 1 to 3 are on every list; 4 and 6 show you have met a dimension that changed too fast or needed both views at once.
Say this
Type 4 splits volatile attributes out of a large dimension into a mini-dimension with its own key, referenced directly from the fact. It stops a million-row customer dimension growing a new Type 2 row every time income band changes. Type 6 combines 1, 2 and 3 on one row: a Type 2 row per version, plus a current-value column kept up to date Type 1 style, so you can report by the value at the time or by the value now.
The reasoning
Type 2 keeps history by adding a row per change. For a dimension with many rows and attributes that change often, that explodes. Kimball's Type 4 answer is the mini-dimension. Move the fast-changing attributes, such as age band and income band, into a small table of every combination, and give the fact a second foreign key to it. The main dimension stays slow.
The mini-dimension is small because it stores combinations, not customers. Ten age bands times ten income bands is a hundred rows. Each fact row points at the combination that was true at the time, so history is preserved without touching the customer dimension.
Type 6 answers a reporting problem. Type 2 alone reports sales by the region the customer was in at the time. The business also wants sales by the customer's current region, restated. Type 6 keeps the Type 2 rows and adds a `current_region` column on every row, overwritten for all versions whenever the region changes.
Type 6 doubles the write work, because a change updates every historical row for that member. Type 7 is Kimball's cheaper variant: keep a durable key on the fact and join to the current row through a view. Both exist because "as it was" and "as it is" are both legitimate questions.
The answer most people give
"Type 4 is keeping a separate history table." That older usage exists, but Kimball's Type 4 is the mini-dimension for rapidly changing attributes. Say which one you mean, because they solve different problems.
They’ll ask next
A customer dimension has 50 million rows and credit score changes monthly. Which type do you reach for, and what does the fact table gain?
What are the valid_from, valid_to and current flag columns on a Type 2 dimension row? How do you query the version that was true on a given date?
Why they ask this
It is the mechanics behind every historical report, and the boundary convention is where bugs live.
Say this
Each Type 2 row carries the period during which it was the truth. valid_from is when the version started, valid_to is when it ended, and is_current marks the open row. The point-in-time query joins the fact's date between valid_from and valid_to. The convention must be fixed: valid_to is either exclusive or inclusive, and the open row holds either null or a far-future date, never a mix.
The reasoning
When a customer moves city, the old row gets valid_to set to the change date and is_current false. A new row is inserted with valid_from at the change date and is_current true. The business key is the same; the surrogate key is new.
The point-in-time join is `ON f.customer_bk = d.customer_bk AND f.order_date >= d.valid_from AND f.order_date < d.valid_to`. With a half-open interval, from inclusive and to exclusive, consecutive versions never overlap and never leave a gap. That is why most teams choose it.
The open row needs a valid_to that the comparison can use. Null forces `OR valid_to IS NULL` into every query and defeats some optimisers. A sentinel such as 9999-12-31 keeps the predicate simple. Pick one and test for it.
is_current is redundant with valid_to but convenient. Current-state queries read `WHERE is_current` and skip the date logic. The failure mode is two current rows for one business key after a bad load, so a uniqueness test on (business key) where is_current is standard.
The answer most people give
"Use BETWEEN valid_from AND valid_to." BETWEEN is inclusive on both ends, so a fact on the change date matches two versions and the row doubles. Use a half-open interval.
They’ll ask next
A report for 15 March shows some customers twice. Which column convention is inconsistent, and what single query finds the offending rows?
What is a slowly changing fact, and how do corrections to old fact rows land in a warehouse? What are the options and their trade-offs?
Why they ask this
Facts are supposed to be immutable, so the interviewer wants to see how you hold that line when the source changes its mind.
Say this
A slowly changing fact is a fact row whose measures change after it was loaded: a refund adjusts an order, a late correction changes a quantity. The options are to update in place, to insert an offsetting row that nets to the correction, or to keep every version with a load timestamp and read the latest. Offsetting rows preserve audit history; in-place updates keep the table simple but erase what was reported before.
The reasoning
Transaction facts are meant to be append-only, because an event happened once. Reality adds corrections. The question is whether yesterday's report should still be reproducible after the correction.
Update in place is simplest: find the row by its natural key and overwrite the measure. The old value is gone, so a report run last week cannot be reproduced. It is acceptable when the business only ever wants the current truth.
Offsetting rows are the accountant's answer. A correction from 100 to 80 inserts a row with minus 20 and a correction flag, dated when it was known. Sums are right by any date, and the audit trail is complete. Row counts no longer equal event counts, so count queries must filter the flag.
Versioned rows keep both: each correction inserts a full new row with a higher load timestamp, and a view picks the latest per key. It supports "what did we report on the first" by filtering on load time. Accumulating snapshot facts, which update as a process moves through milestones, are the designed exception where updates are expected.
The answer most people give
"Fact tables never change; corrections go in a new table." Hiding corrections elsewhere means every report that forgets the second table is wrong. Choose one of the three patterns and apply it in the fact.
They’ll ask next
Finance must reproduce last month's close exactly, even after corrections arrived this week. Which of the three patterns do you pick, and what does the query filter on?
Kimball vs Inmon vs Data VaultSurrogate vs natural keys
What are the hub, link and satellite tables in Data Vault? What does each store, and why does the model split them that way?
Why they ask this
Data Vault is the third name on every architecture list, and most candidates cannot describe its three table types.
Say this
A hub stores one row per business key, and nothing else about it: the key, a hash of it, the load date and the source. A link stores a relationship between hubs, one row per unique combination of their keys. A satellite stores the descriptive attributes of a hub or a link, with a load date, so every change appends a row. The split lets keys, relationships and descriptions change independently without restructuring.
The reasoning
The hub is the list of things the business knows about: every customer number ever seen, every product code. It never changes once a key is inserted. Its job is identity. In Data Vault 2.0 the primary key is a hash of the business key, which lets loads run in parallel without lookups.
The link is a relationship: customer placed order, order contains product. It stores the hash keys of the hubs it connects and its own hash key. Like the hub, it is insert-only. A new relationship adds a row; nothing is updated.
The satellite carries the context: the customer's name, address and status, each row stamped with a load date and the source system. A change in the source inserts a new satellite row. History is kept automatically, like SCD Type 2 without end dates, and the current row is the latest load date.
The reason for the split is auditability and agility. Adding a source adds a satellite without touching the hub. Adding a relationship adds a link. Nothing already loaded is rewritten, which is why Data Vault is sold as the raw, integrated layer. Its cost is query complexity, so a dimensional layer is built on top for consumers.
The answer most people give
"A hub is like a dimension and a link is like a fact." A hub holds only keys, no attributes, and a link holds only relationships, no measures. Dimensions and facts are built from vault tables; they are not the same thing.
They’ll ask next
A second CRM arrives with its own customer attributes. Which Data Vault table do you add, and which existing tables stay untouched?
How do you resolve a many-to-many relationship in a relational model and in a star schema? What goes in the resolving table?
Why they ask this
It is the join that silently multiplies rows, and the fix differs between OLTP and dimensional designs.
Say this
In a relational model, a many-to-many becomes an associative table holding the two foreign keys as a composite primary key, plus any attributes of the relationship itself, such as the date a student enrolled. In a star schema the same shape is a bridge table between a fact or dimension and a multi-valued dimension, often with a group key and an allocation factor so measures do not double.
The reasoning
Relational databases cannot store many-to-many with one foreign key, because a column holds one value. Students take many courses and courses have many students, so an enrolments table holds (student_id, course_id). That pair is unique, so it is the primary key, and attributes that belong to the pair, enrolment date and grade, live there.
In a star schema the problem appears when a fact relates to several members of one dimension at once: a sale with several sales reps, a diagnosis set per visit. Kimball's answer is a bridge table. The fact points at a group key; the bridge maps group key to each member key; the dimension holds the members.
The bridge is where fan-out happens, so it carries an allocation factor when sums must be preserved. It may also carry validity dates when group membership changes over time, which turns it into a Type 2 bridge.
The alternative when the set is small and fixed is to flatten: columns rep_1, rep_2, rep_3 on the fact. It avoids the bridge and breaks as soon as a fourth rep appears. Choose it only when the maximum is a business rule.
The answer most people give
"Put a comma-separated list of ids in one column." It cannot be joined, indexed or tested, and the first analyst to split it writes a different rule from the second.
They’ll ask next
Each support ticket has one to five tags and the business wants ticket counts by tag that also add up to the total. What tables exist, and what column prevents double counting?
What is reference data, and what is a lookup table? How do they differ from master data and from a dimension?
Why they ask this
Three overlapping terms appear in every data governance conversation, and the distinction decides who owns the values.
Say this
Reference data is a small, slowly changing set of allowed values used to classify other data: country codes, currency codes, order statuses. A lookup table stores one such set with its code and description. Master data is the core business entities, customers and products, which have identity and many attributes. In a star schema, reference data usually becomes a small dimension or a junk dimension, and master data becomes the large conformed dimensions.
The reasoning
Reference data answers "what are the valid values". ISO 3166 country codes, ISO 4217 currencies, the eight order statuses your system allows. It is often external or standards-based, changes rarely, and is shared across every system in the company.
A lookup table is the storage: code, name, sometimes a sort order and an active flag. Facts and other tables store the code, and the lookup supplies the readable name. Validating a load against the lookup is the simplest data quality test there is: every code in the fact must exist in the lookup.
Master data is different in kind. A customer has identity, hundreds of attributes, duplicates across systems and a lifecycle. Managing it is MDM: matching, merging, and a golden record. Reference data has none of that complexity; its challenge is agreeing on one list.
Dimensionally, a small reference set such as order status becomes either its own tiny dimension or a column in a junk dimension that bundles several low-cardinality flags. The large master entities become the conformed dimensions on the bus.
The answer most people give
"Reference data and master data are the same; both are dimensions." Reference data is a list of codes you adopt; master data is entities you must match and merge. They are governed and loaded very differently.
They’ll ask next
An order status code appears in the fact that no lookup row describes. Is it a reference data problem or a master data problem, and what does the load do with the row?
What is a late-arriving dimension, and what is an early-arriving fact? What are the standard ways to handle them?
Why they ask this
Every real feed delivers facts before the dimension row exists, and the handling decides whether revenue is lost or misattributed.
Say this
A late-arriving dimension is a dimension row that arrives after facts that reference it; the same event seen from the fact side is an early-arriving fact. Standard handling is to insert a placeholder dimension row for the unknown key, load the fact against it, and update the placeholder when the real row arrives. The alternative is to hold the fact in a suspense table until the dimension exists.
The reasoning
A sale posts at midnight for a customer created at 00:02, and the customer feed runs hourly. When the sales load runs, the customer key is missing. Dropping the row loses revenue; failing the load blocks everything for one row.
The placeholder approach inserts a dimension row with the business key and null or "unknown" attributes, assigns it a surrogate, and loads the fact. When the real attributes arrive, the placeholder is updated in place. The fact already points at the right surrogate, so nothing downstream moves.
The suspense approach parks the fact row until the dimension exists, then loads it. It keeps the dimension clean but delays the fact and needs a process to retry and a report for rows stuck too long.
Under Type 2 the late dimension creates a second problem. A change that arrives late may need a version inserted in the middle of history, with the surrounding valid_from and valid_to adjusted. Facts in that window must be re-pointed. That is why many teams store the business key on the fact as well as the surrogate.
The answer most people give
"Just use a LEFT JOIN so the fact row survives with nulls." The fact then has a null key, breaks the star join, and is excluded by every inner join downstream. The placeholder row keeps the key valid.
They’ll ask next
The real customer attributes arrive two days later and show the customer was in a different region when the sale happened. What changes in the dimension, and does the fact row move?
EvergreenKimball vs Inmon vs Data VaultGrain & fact table types (transaction / periodic snapshot / accumulating)
What is dimensional modeling, and what does it produce?
Why they ask this
The opening question of every warehouse interview; the answer sets how precise the rest will be.
Say this
Dimensional modeling is Kimball's technique for structuring analytical data as facts and dimensions: numeric measurements of business events in fact tables, and the descriptive context for filtering and grouping them in dimension tables. It is optimised for reading and understanding, not for writing.
The reasoning
A business process produces events, and each event has measurements and context. A sale has an amount and a quantity; it happened on a date, in a store, for a product, to a customer. Dimensional modeling stores the measurements in a fact table and each kind of context in a dimension table.
The result is a star: one fact in the centre, dimensions around it, each one join away. Queries read "sum of amount, by product category, for last quarter" as a filter on two dimensions and a sum on the fact.
The design steps are fixed: choose the business process, declare the grain, identify the dimensions, identify the facts. The grain comes before the facts, because a measure that does not fit the grain belongs in another table.
It trades write-time normalization for read-time simplicity. Dimensions are flat and redundant on purpose. Its contrast is Inmon's normalised warehouse and Data Vault's hubs and satellites, both of which usually feed a dimensional layer for consumers anyway.
The answer most people give
"Dimensional modeling is making tables for a dashboard." It is a method with a declared grain, conformed dimensions and additive facts. A table built for one dashboard without a grain statement is not a dimensional model.
They’ll ask next
Name the four design steps in order, and say why grain comes before facts.
EvergreenStar vs snowflakeDimension types (conformed, degenerate, junk, role-playing, bridge)
What is a star schema, and what shape does it draw?
Why they ask this
The shape every BI tool expects, and a one-sentence definition tells the interviewer you have built one.
Say this
A star schema is a fact table in the centre joined directly to a set of flat, denormalised dimension tables, one join each, so that it draws as a star. The fact holds foreign keys and measures; each dimension holds the descriptive attributes for one subject.
The reasoning
The fact table is narrow and long: a surrogate or natural key, a foreign key per dimension, and the measures. The dimensions are wide and short: many descriptive columns, comparatively few rows. Dimension attributes are not normalised into sub-tables; category and department both sit on the product row.
Every query follows the same pattern: filter on dimension attributes, join to the fact on surrogate keys, aggregate measures. Optimisers recognise it, and BI tools model it directly.
The price is redundancy. A category name is repeated on every product row in that category. Columnar storage compresses it away, and a single loading process keeps it consistent, which is why warehouses accept it.
Its contrast is the snowflake schema, where dimensions are normalised into chains of tables, and the galaxy, where several facts share conformed dimensions. A real warehouse is usually a galaxy of stars.
The answer most people give
"A star schema is any set of tables with foreign keys." The star has a declared fact at a stated grain and flat dimensions one join away. A normalised OLTP schema has foreign keys and is not a star.
They’ll ask next
Which part of a star is wide and short, which is narrow and long, and why does that shape help a columnar engine?
What is a snowflake schema, and when would you use it?
Why they ask this
The follow-up to the star, and the "when" half is what separates a memorised answer from a judged one.
Say this
A snowflake schema is a star whose dimensions are normalised into several related tables: product points to category, category points to department. It reduces redundancy and update cost in the dimension at the price of extra joins on every query. It fits when a dimension is very large with big, frequently changing sub-attributes, or when a tool reads it directly from a normalised source.
The reasoning
Take the flat product dimension of a star and pull category into its own table with a key, then department out of category. The product row now holds category_key only. Drawn out, the dimension branches like a snowflake.
Storage drops because the category name appears once, not once per product. A rename touches one row. Those were the strong arguments when storage was expensive and dimensions were updated by hand.
Reads pay for it. A sales-by-department report joins fact to product to category to department. BI tools that expect one join per dimension struggle, and users have to understand the chain.
Kimball's position is to avoid it in the presentation layer and flatten at load time, and to allow outriggers only for a few cases. Snowflaking is reasonable in the integration layer, where tables are loaded rather than queried, and in very large dimensions where the sub-attributes are big and volatile.
The answer most people give
"Snowflake is better because it is normalised." Normalised is better for writes. A presentation layer is read almost only, and the extra joins cost every query, every day.
They’ll ask next
A product dimension has 200 million rows and a 40-column supplier block that changes weekly. Snowflake, outrigger or mini-dimension, and why?
What is a fact table, and what are the kinds of measure it holds?
Why they ask this
The simplest definition in the field, and the additivity part is what most answers miss.
Say this
A fact table records measurements of a business event at a declared grain, one row per event or per snapshot. Its columns are foreign keys to dimensions and numeric measures. Measures are additive if they sum across every dimension, like revenue; semi-additive if they sum across some but not time, like a balance; non-additive if they cannot be summed at all, like a ratio or a unit price.
The reasoning
The grain comes first: "one row per order line", "one row per account per day". Every measure on the row must be true at that grain. Order total does not belong on an order-line row, because summing it would multiply it by the number of lines.
Additive measures are what make a fact useful: sum revenue by any dimension and the answer is right. Semi-additive measures, balances and inventory levels, sum across accounts or stores but not across days; you take the last day's value or an average. Non-additive measures such as margin percent must be recomputed from their additive parts.
Kimball names three fact table types. A transaction fact has a row per event. A periodic snapshot has a row per period per entity, such as daily balance. An accumulating snapshot has one row per process instance, updated as it passes milestones, such as an order from placement to delivery.
Facts are usually the largest tables and are the ones that get partitioned, usually by the event date, and clustered by the keys most filtered.
The answer most people give
"A fact is any number in the warehouse." A product's weight is a number and lives on the dimension, because it describes the product rather than measuring an event. Facts measure events at a grain.
They’ll ask next
Account balance is in a daily snapshot fact. A dashboard sums it over a month and shows thirty times the money. Which additivity class did it ignore, and what should it do?
What is a dimension table, and what are the common dimension types?
Why they ask this
Asked right after "what is a fact", and the type list shows whether you have designed beyond the basics.
Say this
A dimension table holds the descriptive context used to filter, group and label facts: who, what, where, when. It has a surrogate key, a business key and many text attributes. Common types are conformed, shared by several facts; degenerate, a key kept on the fact with no table; junk, a bundle of low-cardinality flags; role-playing, one table used in several roles such as order and ship date; and bridge, which resolves many-to-many.
The reasoning
Dimensions carry the words of a report. "Revenue by region by month" reads region from the customer or store dimension and month from the date dimension. They are wide and comparatively short, and their attributes should be readable text, not codes.
A conformed dimension has the same keys and attributes wherever it is used, so facts can be compared across it. A degenerate dimension is something like order number: it identifies a transaction but has no attributes of its own, so it stays on the fact as a column.
A junk dimension collects small flags, such as payment type, gift flag and channel, into one table of combinations so the fact does not carry a dozen tiny foreign keys. A role-playing dimension is one physical table, usually date, joined several times under different aliases.
A bridge dimension resolves a many-to-many between a fact and a multi-valued dimension, often with an allocation factor. Slowly changing dimensions describe how any of these keeps history, which is a separate axis from type.
The answer most people give
"A dimension is a lookup table." A lookup is one code list. A dimension is a rich, denormalised description of a business entity with history management and a surrogate key, and it may combine many lookups.
They’ll ask next
Order number, gift flag and ship date each need a home. Which dimension type does each become, and which gets no table at all?
EvergreenSurrogate vs natural keysNormalization forms
What is the difference between a primary key and a foreign key?
Why they ask this
The most basic screen question, and a precise answer in one breath buys credibility for the harder ones.
Say this
A primary key uniquely identifies each row in its own table; it is unique and not null. A foreign key is a column in one table that refers to the primary key of another, and it enforces that the referenced row exists. The primary key gives identity; the foreign key gives relationships.
The reasoning
In `customers`, `customer_id` is the primary key: one value per row, never null, never repeated. In `orders`, `customer_id` is a foreign key: it may repeat, because a customer has many orders, and each value must match a customer row.
OLTP databases enforce both. An insert with a duplicate primary key fails; an insert with a foreign key that matches nothing fails. The guarantee is called referential integrity.
Cloud warehouses such as Snowflake, BigQuery and Redshift accept both declarations but, per their documentation, do not enforce them. The pipeline must test uniqueness of the primary key and existence of every foreign key after each load.
In a star schema the fact table's foreign keys point at dimension surrogate keys. The fact's own primary key is usually the composite of those foreign keys plus a degenerate dimension, or a surrogate of its own.
The answer most people give
"A foreign key is the primary key of another table." It references one. The foreign key is a column in the child table, and it can repeat and, if allowed, be null.
They’ll ask next
In a fact table, which columns are foreign keys, and what is its primary key usually made of?
What is normalization, and what do the first three normal forms require?
Why they ask this
Asked in every database interview since Codd, and the three forms must be stated without hesitation.
Say this
Normalization organises tables to store each fact once, so updates cannot create inconsistent copies. First normal form requires atomic values and no repeating groups. Second requires that every non-key column depend on the whole key, not part of a composite key. Third requires that non-key columns depend only on the key, not on another non-key column.
The reasoning
1NF: each cell holds one value, and there are no repeating columns like phone1, phone2, phone3. A list of phone numbers becomes rows in a phones table.
2NF: with a composite key (order_id, product_id), a column such as product_name depends only on product_id, half the key. It moves to a products table. 2NF is automatically satisfied when the key is a single column.
3NF: no transitive dependency. If an orders table holds customer_id and customer_city, city depends on customer, not on order. It moves to customers. The slogan is "the key, the whole key, and nothing but the key".
The purpose is write safety. Each fact in one place means an update cannot leave two versions. OLTP schemas target 3NF or BCNF. Warehouses deliberately denormalise dimensions because they have one writer and many readers.
The answer most people give
"Normalization means splitting tables to make them smaller." It removes specific dependency anomalies. Splitting for size without a dependency reason is just more joins.
They’ll ask next
An orders table carries customer_email. Which normal form does it break, and what is the update anomaly it allows?
EvergreenNormalization formsOne Big Table & wide tables
What is denormalization, and why do warehouses do it?
Why they ask this
The twin of the normalization question, and the interviewer wants the warehouse reason in the answer.
Say this
Denormalization is deliberately storing redundant data, repeating values or pre-joining tables, so reads need fewer joins. It trades write simplicity and storage for query speed and simplicity, which is the right trade in a warehouse where one pipeline writes and many users read.
The reasoning
The normalised form of customer, country and region is three tables. The denormalised form is one customer row with country and region as columns. The region name repeats on every customer in it.
Reads get one join instead of three. Columnar engines compress the repeats, so storage grows less than the row count suggests. BI tools understand a flat dimension directly.
Writes get harder. A region rename updates many rows, and if two jobs load two copies of the same attribute, they can drift. The control is a single loading process and tests that compare the copies.
Star schema dimensions, One Big Table designs and summary tables are all denormalisation done on purpose. The failure mode is denormalising without lineage, so no one knows which copy is authoritative.
The answer most people give
"Denormalization is a mistake you fix with normalization." In a read-heavy warehouse with one writer it is the standard design. The mistake is uncontrolled redundancy, not redundancy.
They’ll ask next
Which single property of a warehouse, compared with an OLTP system, makes denormalization safe enough to be the default?
EvergreenKimball vs Inmon vs Data VaultMedallion / lakehouse layers
What is a data warehouse, and how does it differ from an operational database?
Why they ask this
The field's founding definition; Inmon's four words are expected.
Say this
Inmon defined a data warehouse as a subject-oriented, integrated, time-variant and non-volatile collection of data in support of management decisions. It is organised by business subject rather than application, combines sources into one consistent form, keeps history, and is loaded rather than edited. An operational database serves transactions: current state, many small writes, normalised for consistency.
The reasoning
Subject-oriented: tables are about customers and sales, not about the billing application's screens. Integrated: the same customer from three systems is one customer with one set of codes. Time-variant: history is kept, so last year's view is still available. Non-volatile: data is loaded in batches and not updated by users.
An operational database, OLTP, is the opposite on each axis. It is application-shaped, holds current state, overwrites in place, and is normalised so that thousands of concurrent writes stay consistent.
The warehouse is built for analytical queries: scanning many rows, aggregating, joining a few large tables. That is why it uses columnar storage, denormalised dimensions and partitioning, and why its workload is read-heavy with one writing pipeline.
Modern platforms blur the storage line, a lakehouse holds both raw files and tables, but the definition still holds for the analytical layer: integrated, historical, loaded, organised by subject.
The answer most people give
"A data warehouse is a big database." Size is not the definition. An OLTP database can be larger. The warehouse is defined by integration, history and read-oriented structure.
They’ll ask next
Which of Inmon's four properties does a Type 2 dimension implement, and which one does conformance implement?
EvergreenKimball vs Inmon vs Data VaultNormalization forms
What is entity-relationship modeling, and where is it used compared with dimensional modeling?
Why they ask this
It checks that you know two modeling traditions exist and which one fits which system.
Say this
Entity-relationship modeling describes a domain as entities, their attributes, and the relationships between them with cardinality, usually drawn as an ERD and implemented as a normalised schema. It is the method for operational systems and for an integrated warehouse layer. Dimensional modeling is the method for the analytical presentation layer, with facts and dimensions instead of normalised entities.
The reasoning
Chen introduced the ER model in 1976 as a way to describe data independently of storage. Entities are rectangles, relationships are diamonds or lines, and cardinality is marked at each end. It maps directly to tables, columns and foreign keys.
It produces normalised schemas, because each entity is stored once and relationships are keys. That suits OLTP systems, where many applications write and consistency is the goal.
Inmon's warehouse uses ER modeling for the integrated layer, and Data Vault is a specialised ER style for the same purpose. Kimball skips the normalised layer and models the presentation layer dimensionally from the start.
Most teams use both. The source systems are ER-modelled, the warehouse core may be, and the marts users query are dimensional. Knowing which tradition a table belongs to tells you whether to expect a flat dimension or a chain of joins.
The answer most people give
"ER modeling and dimensional modeling are two notations for the same thing." They produce different schemas for different workloads: normalised entities for writes, facts and dimensions for reads.
They’ll ask next
An order has many lines and each line has one product. Draw it as an ERD in words, then say what the dimensional version of the same business looks like.