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
Heavy stored procedures don’t migrate cleanly into Microsoft Fabric. In this guide, you’ll see how to break down large T‑SQL workloads, rebuild them in notebooks, and wire everything into Lakehouse, Pipelines, and Power BI without losing control or performance.
If you’re planning a wider migration of ETL and reporting logic, it’s worth building a more systematic skillset around Fabric data engineering – for example with a focused course on end‑to‑end Fabric data pipelines.
If your data platform is SQL Server–centric, you probably have:
In Fabric, you can still run T‑SQL in a Warehouse or Lakehouse SQL endpoint, but notebooks give you more:
The goal is not to translate every line 1:1, but to:
Before you open a single notebook, map what you actually have. For each stored procedure, classify it by purpose.
Create a simple inventory table (Excel, OneNote, or a Fabric Lakehouse table) with columns like:
ProcNameCategory (Staging / Transform / Reporting / Utility)Frequency (Daily / Hourly / On-demand)InputTablesOutputTablesCriticality (High / Medium / Low)This gives you a migration map and hints at how to group notebook logic.
You don’t want one giant notebook per stored procedure. Instead, map recurring T‑SQL patterns to notebook patterns.
Old world (SQL Server)
INSERT INTO Stg.Table SELECT ... FROM LinkedServer...Fabric notebook pattern
Example (PySpark) staging cell:
from pyspark.sql.functions import col, current_timestamp
# Parameters (could come from pipeline)
load_date = dbutils.widgets.get("p_load_date")
raw_df = (spark.read
.format("delta")
.load(f"/lakehouse/raw/sales/date={load_date}")
)
stg_df = (raw_df
.dropDuplicates(["OrderID"])
.withColumn("LoadDate", current_timestamp())
)
(stg_df.write
.format("delta")
.mode("overwrite")
.option("overwriteSchema", "true")
.save("/lakehouse/stg/sales")
)
Old world
Fabric notebook pattern
Load, Transform, WriteExample: translating a windowed aggregation from T‑SQL to PySpark.
Original T‑SQL snippet
SELECT
c.CustomerID,
SUM(o.Amount) AS TotalAmount,
ROW_NUMBER() OVER (PARTITION BY c.CustomerID ORDER BY o.OrderDate DESC) AS rn
INTO #CustomerLatest
FROM dbo.Orders o
JOIN dbo.Customers c ON c.CustomerID = o.CustomerID
WHERE o.OrderDate >= DATEADD(year, -1, GETDATE())
GROUP BY c.CustomerID, o.OrderDate;
PySpark equivalent in a notebook
from pyspark.sql.window import Window
from pyspark.sql.functions import sum as _sum, row_number, col
orders_df = spark.read.table("lakehouse.dbo_Orders")
customers_df = spark.read.table("lakehouse.dbo_Customers")
joined = (orders_df.alias("o")
.join(customers_df.alias("c"), col("c.CustomerID") == col("o.CustomerID"))
.where(col("o.OrderDate") >= expr("add_months(current_date(), -12)"))
)
w = Window.partitionBy("c.CustomerID").orderBy(col("o.OrderDate").desc())
latest_df = (joined
.groupBy("c.CustomerID", "o.OrderDate")
.agg(_sum("o.Amount").alias("TotalAmount"))
.withColumn("rn", row_number().over(w))
)
latest_df.write.format("delta").mode("overwrite").save("/lakehouse/curated/customer_latest")
Old world
Fabric notebook pattern
Example: create a SQL view on top of a curated Delta table in Fabric’s SQL endpoint:
CREATE OR ALTER VIEW rpt.SalesSummary AS
SELECT
CustomerID,
OrderDate,
SUM(Amount) AS SalesAmount,
COUNT(*) AS OrderCount
FROM dbo.FactSales
GROUP BY CustomerID, OrderDate;
Then build DAX measures in Power BI on top of this view.
A common anti-pattern is a single 500-line notebook replacing a 500-line stored procedure. Instead, design notebooks for:
In your Fabric workspace, you might adopt a structure like:
01_ingestion/ – raw → staging02_transformation/ – staging → curated03_marts/ – curated → marts / reporting99_utility/ – metadata, logging, common functionsEach folder contains small, focused notebooks:
01_ingestion/load_sales_raw_to_stg02_transformation/build_dim_customer02_transformation/build_fact_sales03_marts/build_sales_mart_dailyInstead of hard-coding dates, schemas, or file paths, use widgets.
# At top of notebook
dbutils.widgets.text("p_run_date", "", "Run Date (YYYY-MM-DD)")
run_date = dbutils.widgets.get("p_run_date")
if not run_date:
from datetime import date
run_date = date.today().isoformat()
print(f"Running for date: {run_date}")
Your pipeline can set p_run_date dynamically, similar to passing parameters into stored procedures.
If you have repeated business rules across stored procedures (e.g., standard customer deduplication), move them into a shared Python module.
# In a shared notebook or .py file
def standardize_customer(df):
from pyspark.sql.functions import upper, trim
return (df
.withColumn("CustomerName", upper(trim("CustomerName")))
.withColumn("Email", lower(trim("Email")))
)
Then import and use in multiple notebooks.
In SQL Server, you might have a master stored procedure that calls others in sequence. In Fabric, use Data Factory Pipelines.
Each pipeline step can:
When adding a Notebook activity in a pipeline:
p_run_date → @pipeline().parameters.run_dateYou can still keep a small SQL script activity for tasks that are naturally T‑SQL, e.g.:
INSERT INTO dbo.ETL_RunLog (PipelineName, RunDate, Status, StartTime)
VALUES (@pipelineName, @runDate, 'Started', SYSUTCDATETIME());
Moving to notebooks doesn’t automatically make things faster. You need to be deliberate about where Spark helps and where SQL is enough.
Keep logic in T‑SQL when:
Example: a slowly changing dimension that’s already efficient in T‑SQL may not benefit from a Spark rewrite.
Consider Spark for:
Basic tuning tips:
repartition / wide joinsOrderDate)(fact_df.write
.format("delta")
.mode("overwrite")
.partitionBy("OrderDate")
.save("/lakehouse/curated/fact_sales")
)
A common risk when rewriting stored procedures is subtle logic drift. Build a simple validation approach.
For a period of time, run both:
Then compare results for key tables:
Example validation query (run on both systems, adjust table names):
SELECT
OrderDate,
COUNT(*) AS RowCount,
SUM(Amount) AS TotalAmount
FROM dbo.FactSales
GROUP BY OrderDate
ORDER BY OrderDate;
You can add lightweight assertions in notebooks.
from pyspark.sql.functions import col
row_count = fact_df.count()
if row_count == 0:
raise ValueError("FactSales has zero rows – aborting")
negative_amounts = fact_df.filter(col("Amount") < 0).count()
if negative_amounts > 0:
raise ValueError(f"Found {negative_amounts} negative amounts – check source data")
If a check fails, the notebook fails, the pipeline fails, and you get a clear error instead of silent bad data.
Don’t try to “lift and shift” each stored procedure into its own notebook. Start by mapping your procedures into a small set of reusable patterns (staging, transform, marts), design a notebook layout and pipeline flow around those patterns, and only then begin rewriting. You’ll end up with a simpler, more testable Fabric solution instead of a 1:1 reimplementation of yesterday’s complexity.
Microsoft Fabric
New
Next Batches Now Live
Power BI
SQL
Power Apps
Power Automate
Microsoft Fabrics
Azure Data Engineering