Business Professionals
Power BI | Power Pivot | Power Query | DAX
Cloud Flows | RPA | AI Builder | Copilot
60+ Formulas | Data Stories | Advanced Reporting & Modeling
VB Programming | Report Automation |
MS-Office Automation
Techno-Business Professionals
Power BI | Power Query | Advanced DAX | SQL - Query &
Programming
Microsoft Fabric | Power BI | Power Query | Advanced DAX |
SQL - Query & Programming
Power BI | Power Apps | Power Automate | Copilot Studio | Power Pages | Dataverse
Microsoft Power Apps | Microsoft Power Automate
Power BI | Adv. DAX | SQL (Query & Programming) |
VBA | Python | Web Scrapping | API Integration
Power BI | Power Apps | Power Automate |
SQL (Query & Programming)
Power BI | Adv. DAX | Power Apps | Power Automate |
SQL (Query & Programming) | VBA | Python | Web Scrapping | API Integration
Power Apps | Power Automate | SQL | VBA | Python |
Web Scraping | RPA | API Integration
Technology Professionals
Power BI | DAX | SQL | ETL with SSIS | SSAS | VBA | Python
Power BI | SQL | Azure Data Lake | Synapse Analytics |
Data Factory | Databricks | Power Apps | Power Automate |
Azure Analysis Services
Microsoft Fabric | Power BI | SQL | Lakehouse |
Data Factory (Pipelines) | Dataflows Gen2 | KQL | Delta Tables | Power Apps | Power Automate
Power BI | Power Apps | Power Automate | SQL | VBA | Python | API Integration
Power BI | Advanced DAX | Databricks | SQL | Lakehouse Architecture
Business Professionals
Power BI | Power Pivot | Power Query | DAX
Cloud Flows | RPA | AI Builder | Copilot
60+ Formulas | Data Stories | Advanced Reporting & Modeling
VB Programming | Report Automation |
MS-Office Automation
Techno-Business Professionals
Power BI | Power Query | Advanced DAX | SQL - Query &
Programming
Microsoft Fabric | Power BI | Power Query | Advanced DAX |
SQL - Query & Programming
Power BI | Power Apps | Power Automate | Copilot Studio | Power Pages | Dataverse
Microsoft Power Apps | Microsoft Power Automate
Power BI | Adv. DAX | SQL (Query & Programming) |
VBA | Web Scrapping | API Integration
Power BI | Power Apps | Power Automate |
SQL (Query & Programming)
Power BI | Adv. DAX | Power Apps | Power Automate |
SQL (Query & Programming) | VBA | Web Scrapping | API Integration
Power Apps | Power Automate | SQL | VBA |
Web Scraping | RPA | API Integration
Technology Professionals
Power BI | DAX | SQL | ETL with SSIS | SSAS | VBA
Power BI | SQL | Azure Data Lake | Synapse Analytics |
Data Factory | Azure Analysis Services
Microsoft Fabric | Power BI | SQL | Lakehouse |
Data Factory (Pipelines) | Dataflows Gen2 | KQL | Delta Tables
Power BI | Power Apps | Power Automate | SQL | VBA | API Integration
Power BI | Advanced DAX | Databricks | SQL | Lakehouse Architecture
LEARN THIS HANDS ON
Microsoft Fabric & Power BI
You already know how to spin up a Lakehouse in Fabric; the real question is how to shape it so Sales and Finance can trust and reuse it. This article walks through concrete star-schema patterns in a Microsoft Fabric Lakehouse for sales and finance data, with table layouts, naming, and code examples you can lift into your own project.
If you want to go deeper into end‑to‑end architecture and governance around these patterns, a structured path like a dedicated Fabric-focused data engineering track can help you move faster than trial‑and‑error.
You’re still designing facts and dimensions, but the constraints are different from classic warehouse-on-SQL:
For Sales and Finance, the pattern that works well is:
This article focuses on Gold and assumes you’ve already done the heavy lifting in Bronze/Silver.
Before we dive into concrete tables, align on a few design rules that work well in Fabric:
Use a predictable, layer-aware naming convention:
lh_sales_finance (project/domain based).silver_erp, silver_crm, silver_hrgold_starf_sales_invoice, f_sales_order, f_gl_balanced_customer, d_product, d_date, d_cost_centerThis keeps Fabric’s SQL Endpoint and Power BI dataset views clean and predictable.
In Fabric Lakehouse, you still want surrogate keys:
customer_key, product_key, date_key, cost_center_key.Pattern:
d_customer.customer_key (INT, identity or hash).d_customer.customer_code (business key from ERP).f_sales_invoice.customer_key + f_sales_invoice.customer_code.This lets you:
Fabric’s Delta tables support partitioning. For Sales and Finance facts:
invoice_date_key (or invoice_date), monthly.posting_date_key or fiscal_period.Example partitioning fields:
partition_year (INT)partition_month (INT)You can derive these in your ETL so queries that filter by date hit fewer files.
Let’s design a realistic Sales star that both Sales and Finance can use.
f_sales_invoiceGrain: one row per invoice line.
Core columns:
sales_invoice_key (surrogate, optional)invoice_line_id (business line ID)invoice_id (business header ID)customer_key, product_key, date_key, sales_org_key, sales_rep_keyquantityunit_pricegross_amountdiscount_amountnet_amounttax_amountcurrency_codeinvoice_typeis_credit_memoExample: creating f_sales_invoice in a Fabric Notebook with PySpark:
from pyspark.sql import functions as F
silver_sales = spark.read.table("silver_erp.sales_invoice_lines")
f_sales_invoice = (
silver_sales
.withColumn("date_key", F.date_format("invoice_date", "yyyyMMdd").cast("int"))
.withColumn("partition_year", F.year("invoice_date"))
.withColumn("partition_month", F.month("invoice_date"))
.select(
F.col("invoice_line_id"),
F.col("invoice_id"),
F.col("customer_key"),
F.col("product_key"),
F.col("sales_org_key"),
F.col("sales_rep_key"),
F.col("date_key"),
F.col("currency_code"),
F.col("invoice_type"),
F.col("is_credit_memo"),
F.col("quantity"),
F.col("unit_price"),
F.col("gross_amount"),
F.col("discount_amount"),
F.col("net_amount"),
F.col("tax_amount"),
F.col("partition_year"),
F.col("partition_month")
)
)
(
f_sales_invoice
.write
.format("delta")
.mode("overwrite")
.partitionBy("partition_year", "partition_month")
.saveAsTable("gold_star.f_sales_invoice")
)
d_customercustomer_key (INT)customer_code (business key)customer_namecustomer_groupindustrycountry, citypayment_termsis_actived_productproduct_keyproduct_codeproduct_namebrandcategorysub_categoryuomis_actived_sales_org / d_sales_repd_sales_org: region, channel, division.d_sales_rep: sales person, team, manager.These are straightforward dimensions, but in Fabric you’ll often build them with Delta merges from Silver.
Example: building d_customer with SQL in a Lakehouse SQL Endpoint:
CREATE OR REPLACE TABLE gold_star.d_customer
USING DELTA
AS
SELECT
ROW_NUMBER() OVER (ORDER BY customer_code) AS customer_key,
customer_code,
customer_name,
customer_group,
industry,
country,
city,
payment_terms,
is_active
FROM silver_erp.customer_master;
For production, switch to MERGE to support slowly changing dimensions.
d_dateRe-use the same d_date for Sales and Finance.
Minimal structure:
date_key (INT, yyyyMMdd)date (DATE)year, month, daymonth_name, quarterfiscal_year, fiscal_period, fiscal_quarterFabric Notebook example:
from pyspark.sql import functions as F
from pyspark.sql import types as T
start_date = "2015-01-01"
end_date = "2030-12-31"
dates_df = spark.range(0, F.datediff(F.lit(end_date), F.lit(start_date)) + 1) \
.withColumn("date", F.expr(f"date_add('{start_date}', id)")) \
.select("date") \
.withColumn("date_key", F.date_format("date", "yyyyMMdd").cast("int")) \
.withColumn("year", F.year("date")) \
.withColumn("month", F.month("date")) \
.withColumn("day", F.dayofmonth("date")) \
.withColumn("month_name", F.date_format("date", "MMM")) \
.withColumn("quarter", F.quarter("date"))
# Add fiscal logic as needed
(
dates_df
.write
.format("delta")
.mode("overwrite")
.saveAsTable("gold_star.d_date")
)
Finance usually wants a General Ledger view aligned with Sales.
f_gl_balanceYou have two common grains:
In a Lakehouse, you can support both, but make them separate facts.
f_gl_transactionGrain: one row per GL posting line.
Columns:
gl_trx_id (business ID)account_keycost_center_keydate_keycompany_keydebit_amountcredit_amountamount_localamount_groupcurrency_codedocument_typeposting_periodf_gl_balanceGrain: one row per account / cost center / period.
Columns:
account_keycost_center_keyfiscal_period_key (or date_key representing month end)company_keyopening_balancedebit_amountcredit_amountclosing_balanceYou can build f_gl_balance by aggregating f_gl_transaction in a scheduled Fabric Dataflow Gen2 or Notebook.
Example SQL aggregation:
CREATE OR REPLACE TABLE gold_star.f_gl_balance
USING DELTA
AS
SELECT
account_key,
cost_center_key,
company_key,
fiscal_period_key,
SUM(opening_balance) AS opening_balance,
SUM(debit_amount) AS debit_amount,
SUM(credit_amount) AS credit_amount,
SUM(opening_balance + debit_amount - credit_amount) AS closing_balance
FROM silver_erp.gl_transactions_periodic
GROUP BY
account_key,
cost_center_key,
company_key,
fiscal_period_key;
d_accountaccount_keyaccount_codeaccount_nameaccount_type (P&L, Balance Sheet)account_group (Revenue, COGS, etc.)ifrs_category (if used)d_cost_centercost_center_keycost_center_codecost_center_namedepartmentcost_center_groupd_companycompany_keycompany_codecompany_namecountrycurrency_codeThese dimensions should share conformed attributes with Sales where it makes sense (e.g., same d_company, same d_date).
The value of a Lakehouse star is cross-domain analysis: margin by customer, P&L by product, etc.
Make these shared between Sales and Finance facts:
d_dated_companyd_product (if Finance tracks product-level COGS).This enables:
Once your Power BI model is connected to the Fabric Lakehouse (via Direct Lake or import), you can build reconciliation measures.
Sales Revenue :=
SUM ( 'f_sales_invoice'[net_amount] )
GL Revenue :=
CALCULATE (
SUM ( 'f_gl_transaction'[amount_local] ),
'd_account'[account_group] = "Revenue"
)
Revenue Difference := [Sales Revenue] - [GL Revenue]
This only works reliably if:
f_sales_invoice and f_gl_transaction both relate to the same d_date and d_company.You can build Gold stars using either Notebooks or Dataflows Gen2. For Sales and Finance, a hybrid approach works well:
Typical pattern from silver_erp to gold_star:
last_modified_date in Silver.MERGE into the Gold fact.Example SQL MERGE for f_sales_invoice:
MERGE INTO gold_star.f_sales_invoice AS tgt
USING staging.f_sales_invoice_delta AS src
ON tgt.invoice_line_id = src.invoice_line_id
WHEN MATCHED THEN UPDATE SET
tgt.customer_key = src.customer_key,
tgt.product_key = src.product_key,
tgt.net_amount = src.net_amount,
tgt.tax_amount = src.tax_amount,
tgt.quantity = src.quantity,
tgt.unit_price = src.unit_price
WHEN NOT MATCHED THEN INSERT (
invoice_line_id,
invoice_id,
customer_key,
product_key,
sales_org_key,
sales_rep_key,
date_key,
currency_code,
invoice_type,
is_credit_memo,
quantity,
unit_price,
gross_amount,
discount_amount,
net_amount,
tax_amount,
partition_year,
partition_month
)
VALUES (
src.invoice_line_id,
src.invoice_id,
src.customer_key,
src.product_key,
src.sales_org_key,
src.sales_rep_key,
src.date_key,
src.currency_code,
src.invoice_type,
src.is_credit_memo,
src.quantity,
src.unit_price,
src.gross_amount,
src.discount_amount,
src.net_amount,
src.tax_amount,
src.partition_year,
src.partition_month
);
Schedule this in a Fabric Pipeline to keep Gold aligned with Silver.
For Sales and Finance, you usually need SCD Type 2 for:
d_customer (changes in customer group, payment terms).d_cost_center (department changes).Pattern:
valid_from, valid_to, is_current to dimensions.In Fabric, implement SCD using MERGE with conditions on business key and effective dates. Keep it simple at first (only track critical attributes) to avoid exploding your dimension size.
Pick one fact table (e.g., f_sales_invoice) and two shared dimensions (d_date, d_company) and implement them in your Fabric Lakehouse Gold layer using the patterns above. Once that thin star is stable and used in Power BI, extend it with Finance (f_gl_transaction, d_account, d_cost_center) instead of trying to model the entire Sales and Finance universe in one shot.
Microsoft Fabric
New
Next Batches Now Live
Power BI
SQL
Power Apps
Power Automate
Microsoft Fabrics
Azure Data Engineering