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
You have a modern BI stack in Azure, multiple data sources, and a pile of ETL logic that somehow ended up split between SQL scripts, pipelines, and Power BI. This article shows how to deliberately choose between SQL, Azure Data Factory, and Power BI Dataflows for each ETL step in a modern BI stack, and how to keep your architecture from turning into a spaghetti of transformations.
If you want to go deeper into designing end‑to‑end cloud pipelines that play nicely with Power BI, have a look at this practical course on cloud data engineering for BI.
What it is:
Strengths:
Weaknesses:
What it is:
Strengths:
Weaknesses:
What it is:
Strengths:
Weaknesses:
Instead of asking “SQL or Data Factory or Dataflows?”, design around layers. Then assign the right tool to each layer.
Typical layers in an Azure BI stack:
This isn’t rigid, but it gives you a safe default. Deviate only with a reason.
Use SQL when you have to:
Assume you’ve landed data into stgSales, stgCustomer, stgProduct. Your warehouse schema might look like this:
-- DimCustomer
CREATE OR ALTER VIEW dw.DimCustomer AS
SELECT
c.CustomerKey,
c.CustomerID,
c.CustomerName,
c.Region,
c.Segment,
c.IsActive,
c.ValidFrom,
c.ValidTo
FROM stg.CustomerSCD c;
-- FactSales
CREATE OR ALTER VIEW dw.FactSales AS
SELECT
s.SalesKey,
s.SalesDate,
c.CustomerKey,
p.ProductKey,
s.Quantity,
s.NetAmount,
s.DiscountAmount,
s.CurrencyCode
FROM stg.Sales s
JOIN dw.DimCustomer c
ON s.CustomerID = c.CustomerID
AND s.SalesDate BETWEEN c.ValidFrom AND c.ValidTo
JOIN dw.DimProduct p
ON s.ProductID = p.ProductID;
Why SQL here?
ValidFrom/ValidTo) are easier to reason about in SQLAvoid pushing tasks to SQL that are better handled upstream:
For those, let Data Factory do the orchestration.
Use Azure Data Factory as the conductor of your ETL orchestra.
Typical ADF responsibilities:
Typical daily pipeline:
Sales from on‑prem SQL to landing.Sales in Azure SQLstg.Salesdw.FactSalesThe SQL pieces might look like:
-- Step 2: Landing -> Staging
CREATE OR ALTER PROCEDURE etl.LoadStgSales AS
BEGIN
SET NOCOUNT ON;
TRUNCATE TABLE stg.Sales;
INSERT INTO stg.Sales (SalesID, SalesDate, CustomerID, ProductID, Quantity, NetAmount)
SELECT
SalesID,
SalesDate,
CustomerID,
ProductID,
Quantity,
NetAmount
FROM landing.Sales;
END;
GO
-- Step 3: Staging -> Warehouse
CREATE OR ALTER PROCEDURE etl.LoadFactSales AS
BEGIN
SET NOCOUNT ON;
-- Upsert logic, simplified
MERGE dw.FactSalesBase AS tgt
USING (
SELECT * FROM stg.Sales
) AS src
ON tgt.SalesID = src.SalesID
WHEN MATCHED THEN
UPDATE SET
tgt.Quantity = src.Quantity,
tgt.NetAmount = src.NetAmount
WHEN NOT MATCHED BY TARGET THEN
INSERT (SalesID, SalesDate, CustomerID, ProductID, Quantity, NetAmount)
VALUES (src.SalesID, src.SalesDate, src.CustomerID, src.ProductID, src.Quantity, src.NetAmount);
END;
GO
ADF just orchestrates:
landing.Salesetl.LoadStgSalesetl.LoadFactSalesADF is best as the glue, not the place where every business rule lives.
Power BI Dataflows are excellent for last‑mile shaping and self‑service scenarios.
Use Dataflows when:
Assume you already have dw.FactSales and dw.DimDate in Azure SQL. A Dataflow could:
FactSales with DimDateSalesSummary entity for multiple datasetsPower Query (M) might look like this:
let
Source = Sql.Database("azuresqlserver.database.windows.net", "SalesDW"),
FactSales = Source{[Schema="dw",Item="FactSales"]}[Data],
DimDate = Source{[Schema="dw",Item="DimDate"]}[Data],
Merged = Table.NestedJoin(
FactSales,
{"SalesDateKey"},
DimDate,
{"DateKey"},
"DateTable",
JoinKind.Inner
),
Expanded = Table.ExpandTableColumn(
Merged,
"DateTable",
{"CalendarDate", "FiscalYear", "FiscalMonth"},
{"CalendarDate", "FiscalYear", "FiscalMonth"}
),
Grouped = Table.Group(
Expanded,
{"FiscalYear", "FiscalMonth"},
{{"TotalSales", each List.Sum([NetAmount]), type number}}
)
in
Grouped
Why Dataflows here?
SalesSummary can feed multiple datasetsWhen you’re unsure where a transformation belongs, ask these questions.
For most teams, a simple and robust pattern looks like this:
This keeps heavy lifting and shared logic in SQL, orchestration in ADF, and last‑mile business shaping in Dataflows.
Pick one real pipeline you own today and do this:
Repeat this cleanup a few times and you’ll gradually move from an accidental mix of SQL, Data Factory, and Dataflows to a deliberate, maintainable ETL design.
Azure
New
Next Batches Now Live
Power BI
SQL
Power Apps
Power Automate
Microsoft Fabrics
Azure Data Engineering