Creating Fact and Dimension Tables
Complete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
✦ Skip the page breaks and see fewer ads — read each lesson on a single page with Pro
Lesson: Creating Fact and Dimension Tables
Introduction: The Foundation of Data Architecture
In the world of data engineering and business intelligence, the way you organize your data determines how easily you can derive value from it. If you dump all your raw data into a single, massive table, you will quickly find that queries are slow, updates are dangerous, and the logic required to answer simple business questions becomes incredibly complex. This is where dimensional modeling comes into play. By structuring your data into Fact and Dimension tables, you transform a chaotic "data swamp" into a clean, navigable, and high-performing data warehouse.
This lesson focuses on the core concepts of dimensional modeling—specifically, the Star Schema. You will learn how to distinguish between quantitative data (Facts) and descriptive data (Dimensions), how to design these tables to support business requirements, and how to implement them using SQL. Understanding this structure is essential for anyone working with data because it is the industry-standard way to enable fast reporting, intuitive data exploration, and reliable analytical outcomes. Whether you are building an internal dashboard or an enterprise-grade reporting platform, the principles covered here will serve as the backbone of your work.
Understanding the Dimensional Model
At its simplest, dimensional modeling is a design technique for databases that makes data easy to understand and quick to query. The two primary components are Fact tables and Dimension tables. Before we dive into the "how-to," let’s clarify what these terms mean in practice.
What is a Fact Table?
A Fact table contains the quantitative data or "metrics" resulting from business processes. These are the numbers you want to sum, average, or count. For example, in a retail store, a record of a sale—the price, the quantity, and the tax paid—is a fact. Fact tables are usually very long and narrow. They contain foreign keys that point to dimension tables and the numerical values (measures) that represent the business activity.
What is a Dimension Table?
A Dimension table contains the descriptive attributes of the business. If the Fact table tells you how many items were sold, the Dimension tables tell you what those items were, who bought them, when they were bought, and where the transaction took place. Dimensions provide the context for the numbers. They are generally shorter than fact tables but much wider, as they contain many text-based columns that describe the entities involved in the business process.
Callout: The Star Schema Analogy Think of a Star Schema like a star in the night sky. The Fact table sits at the center, representing the core event (e.g., a sale). The Dimension tables are the points of the star, radiating outward. Each point provides a specific context—Product, Customer, Date, or Location. By connecting the center to the points, you can answer complex questions like "How many blue shirts did customers in New York buy in the third quarter?"
Designing Fact Tables: Best Practices
Designing a fact table requires a deep understanding of the business process. You must decide what constitutes a "grain"—the lowest level of detail you will store. If you store data at the transaction level, you can aggregate it up to the daily, monthly, or yearly level later. However, if you store data at the daily level, you can never "drill down" into individual transactions.
Selecting the Grain
The grain is the most important decision in your design. A common mistake is to try to summarize data too early. Always aim for the lowest level of detail available. For instance, if you are tracking website visits, the grain should be a single page view, not a daily total per user. Storing the raw transaction allows you to perform any future analysis without re-importing the data.
Identifying Measures
Measures are the columns that you perform math on. These typically fall into three categories:
- Additive: Measures that can be summed across any dimension (e.g., Sales Amount, Quantity Sold).
- Semi-Additive: Measures that can be summed across some dimensions but not others (e.g., Current Inventory Level—you can sum inventory across all stores, but you cannot sum it across time because you would be double-counting the same stock).
- Non-Additive: Measures that cannot be summed (e.g., Price, Ratios, or Percentages).
Handling Foreign Keys
Your fact table should contain foreign keys that link directly to the primary keys of your dimension tables. Avoid putting descriptive text in your fact table. If you find yourself adding a column like "Product_Name" to your fact table, you have violated the rules of dimensional modeling. That information belongs in the Dim_Product table.
Designing Dimension Tables: Best Practices
Dimension tables are the "nouns" of your data warehouse. They describe the people, places, and things involved in your business. A well-designed dimension table is easy for a human to read and efficient for a database to process.
Denormalization
Unlike operational databases (OLTP) which prioritize avoiding data duplication, data warehouses (OLAP) often intentionally duplicate data. This is called denormalization. For example, in a normalized database, you might have a City table, a State table, and a Country table. In a dimension table, you should flatten these into a single Geography dimension. This makes queries simpler because you don't have to perform multiple "JOIN" operations to get a full address.
Surrogate Keys
Never use the source system's natural keys (like an ID from a legacy application) as the primary key in your dimension table. Instead, create a "Surrogate Key"—a simple integer that is unique to the data warehouse. This allows you to handle changes in the source data, such as a customer changing their ID, without breaking your historical reporting.
Note: Why Surrogate Keys Matter Imagine a customer changes their email address, which was being used as a unique identifier. If you didn't have a surrogate key, all historical sales linked to that email would effectively become "orphaned" or require a massive update across millions of rows. A surrogate key remains constant regardless of changes in the business logic or source systems.
Step-by-Step: Creating a Fact and Dimension Table
Let's walk through a practical scenario. Suppose we are building a sales reporting system for an e-commerce platform. We have a raw data table called raw_orders. We need to create a Fact_Sales table and a Dim_Product table.
Step 1: Create the Dimension Table
First, we create the dimension table. We want to include descriptive attributes that analysts might use to filter or group their reports.
CREATE TABLE Dim_Product (
Product_SK SERIAL PRIMARY KEY, -- Surrogate Key
Product_ID VARCHAR(50), -- Original Source ID
Product_Name VARCHAR(255),
Category VARCHAR(100),
Brand VARCHAR(100),
Color VARCHAR(50),
Size VARCHAR(20)
);
Step 2: Create the Fact Table
Next, we create the fact table. It will contain the surrogate key from the dimension table and the numerical measures.
CREATE TABLE Fact_Sales (
Sale_ID SERIAL PRIMARY KEY,
Date_Key INT, -- Link to a Date Dimension
Product_SK INT REFERENCES Dim_Product(Product_SK),
Customer_SK INT, -- Link to a Customer Dimension
Quantity_Sold INT,
Unit_Price DECIMAL(10, 2),
Total_Amount DECIMAL(12, 2)
);
Step 3: Loading the Data
When loading the data, you must perform a lookup. You take the Product_ID from your raw source, find the corresponding Product_SK in the Dim_Product table, and insert that key into the Fact_Sales table.
-- Example of inserting a record into the fact table
INSERT INTO Fact_Sales (Date_Key, Product_SK, Customer_SK, Quantity_Sold, Unit_Price, Total_Amount)
SELECT
20231027,
p.Product_SK,
c.Customer_SK,
1,
49.99,
49.99
FROM raw_orders o
JOIN Dim_Product p ON o.source_product_id = p.Product_ID
JOIN Dim_Customer c ON o.source_customer_id = c.Customer_ID;
Common Pitfalls and How to Avoid Them
Even experienced data professionals fall into traps when building dimensional models. Here are the most common mistakes and how to steer clear of them.
1. Mixing Facts and Dimensions
A common beginner mistake is putting "Product Description" in the "Sales" table. If you do this, you lose the ability to easily update the product description without updating millions of historical sales records. Keep facts strictly for numbers and dimensions strictly for descriptions.
2. Ignoring Slowly Changing Dimensions (SCD)
What happens if a product changes its category? If you just update the record in the dimension table, you will change the history. For example, if a "Tablet" was categorized as "Electronics" but later moved to "Office Supplies," you might suddenly find that all your historical sales for that tablet are now attributed to "Office Supplies." You need to implement SCD Type 2, which involves adding "Effective Date" and "End Date" columns to your dimension tables to track changes over time.
3. Over-Normalization
Some developers come from a software engineering background and try to apply "3rd Normal Form" (3NF) to their data warehouse. While 3NF is great for transaction processing, it is terrible for analytical queries. Do not be afraid of redundant data in your dimension tables. If a user needs to see the "Category" and "Sub-category" together, include both in the same table, even if it feels redundant.
4. Poor Date Handling
Never rely on just a timestamp string. Always create a dedicated Dim_Date table. This allows you to easily query by "Fiscal Quarter," "Day of Week," "Holiday Status," or "Season." Trying to calculate these values on the fly using SQL functions is slow and error-prone.
Callout: The Power of a Date Dimension A
Dim_Datetable is arguably the most useful dimension in any warehouse. It acts as a bridge between your business events and the human calendar. By pre-calculating attributes like 'Is_Weekend' or 'Fiscal_Year', you remove the need for complex, repetitive SQL logic in your reports, making them faster and easier to maintain.
Comparison: Star Schema vs. Snowflake Schema
When designing your dimensions, you may encounter the debate between the Star Schema and the Snowflake Schema.
| Feature | Star Schema | Snowflake Schema |
|---|---|---|
| Structure | Denormalized (Flat) | Normalized (Hierarchical) |
| Complexity | Simple, easy to join | Complex, many tables |
| Query Speed | Very fast | Slower due to more joins |
| Maintenance | Easy to maintain | Harder to maintain |
| Data Redundancy | Higher | Lower |
Recommendation: In almost all modern data warehousing scenarios, the Star Schema is the preferred approach. While it uses more disk space due to redundancy, storage is cheap, whereas human time spent writing complex SQL queries is expensive.
Best Practices for Performance
Performance is a key concern when dealing with large datasets. As your fact tables grow into the millions or billions of rows, the design of your tables becomes critical.
Partitioning
Partition your fact tables by date. If your users are mostly querying the last 12 months of data, partitioning your table by month or year allows the database engine to completely ignore the data that isn't needed. This can reduce query time from minutes to seconds.
Indexing
Ensure that your foreign keys in the fact table are indexed. When a user joins Fact_Sales to Dim_Product, the database engine needs to find the matching row quickly. A B-tree index on the Product_SK column in the fact table is essential for this operation.
Data Types
Be mindful of your data types. Using a BIGINT when a SMALLINT would suffice wastes memory and disk space. Furthermore, consistently using the same data types for keys across tables is vital for performance. If your Product_SK is an INT in the dimension table but a BIGINT in the fact table, the database might perform an implicit type conversion during every join, which slows down the query.
Handling Special Scenarios
Degenerate Dimensions
Sometimes, you have a piece of information that doesn't really belong in a dimension table, like an Invoice Number. Since an invoice number is unique to a single transaction, it doesn't need its own table. You can keep it directly in the Fact table. This is known as a "Degenerate Dimension." It’s perfectly acceptable to include it for the sake of traceability.
Junk Dimensions
What if you have many small flags, like "Promotion_Applied," "Gift_Wrapped," or "Return_Flag"? Creating a separate table for each one is overkill. Instead, you can create a "Junk Dimension"—a single table that contains every possible combination of these flags. This keeps your fact table clean while still allowing for easy filtering.
Step-by-Step: Implementing an SCD Type 2 Dimension
Implementing a Slowly Changing Dimension (SCD) Type 2 is a standard requirement for tracking history. Here is how you do it.
- Add Tracking Columns: Add
is_current,effective_date, andend_dateto yourDim_Producttable. - Expire the Old Record: When a change occurs, update the existing record by setting
is_currenttofalseand theend_dateto the current timestamp. - Insert the New Record: Insert a new row for the product with the updated information, setting
is_currenttotrueandeffective_dateto the current timestamp.
This allows you to run a query for a date in the past and see exactly what the product name or category was at that specific time.
-- Example of marking an old record as expired
UPDATE Dim_Product
SET is_current = FALSE,
end_date = CURRENT_DATE
WHERE Product_ID = 'PROD-001' AND is_current = TRUE;
-- Inserting the new, updated record
INSERT INTO Dim_Product (Product_ID, Product_Name, Category, is_current, effective_date)
VALUES ('PROD-001', 'Updated Name', 'New Category', TRUE, CURRENT_DATE);
Common Questions (FAQ)
Q: How many dimensions should a fact table have? A: There is no strict limit. However, a table with more than 10-15 dimensions can become difficult to manage. If you have too many, consider if some dimensions can be combined or if you are trying to solve too many business problems with a single fact table.
Q: Should I use views instead of physical dimension tables? A: Views can be useful for minor transformations, but for large-scale data warehouses, physical tables are better. They allow you to define indexes, partitions, and storage settings that are not possible with standard views.
Q: What if my data doesn't fit into a Star Schema? A: Not every business process is a clean sale. If you have complex, multi-stage processes (like a supply chain), you might need a "Fact Constellation" (multiple fact tables sharing common dimensions). Start with a Star Schema and only add complexity if the business requirements demand it.
Q: How often should I refresh my dimension tables? A: This depends on your business needs. If your report needs to reflect the latest organizational changes, you might need a real-time refresh. If daily reporting is sufficient, a nightly batch process is standard and much easier to maintain.
Summary of Key Takeaways
Creating fact and dimension tables is the process of building a language that your business can use to speak about its data. By following the principles of dimensional modeling, you ensure that your data is not just stored, but organized in a way that is logical, performant, and reliable.
- Define the Grain: Always start by identifying the lowest level of detail for your fact tables. This provides the most flexibility for future analysis.
- Separate Context from Content: Keep quantitative measures in Fact tables and descriptive attributes in Dimension tables. Never mix these two roles.
- Use Surrogate Keys: Decouple your data warehouse from the source system by using unique, internal integer keys for all dimension records.
- Embrace Denormalization: Do not be afraid to duplicate data in your dimension tables if it simplifies your queries. The goal is to make the data easy for users to navigate.
- Build a Date Dimension: A dedicated
Dim_Datetable is essential for any analytical system. It simplifies time-based reporting significantly. - Handle History with SCD: Use Slowly Changing Dimension (SCD) Type 2 patterns to ensure that your historical data remains accurate even when business attributes change over time.
- Prioritize Readability: The ultimate goal of a dimensional model is to make data accessible. If an analyst cannot understand your table structure within a few minutes, the design is likely too complex.
By mastering these concepts, you move beyond simple data storage and into the realm of true data architecture. You are no longer just moving bytes; you are creating a reliable, high-performance foundation that allows your organization to make evidence-based decisions. Start small, focus on the grain, and keep your schema clean—your future self (and your users) will thank you.
Continue the course
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons