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
Marketing teams in Chicago keep asking the same Monday morning questions: Did our paid spend actually move pipeline? Which campaigns can we cut without hurting revenue? Most “Power BI for marketing” reports answer none of that – they’re just pretty channel summaries.
This walkthrough shows how to build a Power BI dashboard a CMO actually uses every Monday: one view that ties spend, funnel, and revenue together, with enough detail that a marketing data analyst can defend every number.
You’re the marketing data analyst at a mid-size B2B company based in Chicago. Your stack looks roughly like this:
You already have several Power BI reports:
The CMO hates this:
The goal: one CMO Monday dashboard in Power BI that answers:
We’ll build that around three core tables and a few key measures.
You can’t fix a CMO dashboard with visuals alone. You need a model that reflects the funnel.
For this scenario, keep it lean:
Assuming Import mode in Power BI Desktop and standard star schema:
DimDate[Date] → many-to-one to FactSpend[SpendDate]DimDate[Date] → many-to-one to FactLeads[LeadDate]DimDate[Date] → many-to-one to FactOpportunities[CreatedDate]DimChannel[ChannelKey] → many-to-one to each fact table’s ChannelKeyDimCampaign[CampaignKey] → many-to-one to each fact table’s CampaignKeyUse a single active relationship from DimDate to each fact, and rely on USERELATIONSHIP only when you truly need alternate date logic (e.g., opportunity close date vs created date).
Create DimDate in Power Query or DAX. For a CMO dashboard where you want flexible relative periods, a DAX calendar in a dedicated table works well:
DimDate =
ADDCOLUMNS (
CALENDAR ( DATE ( YEAR ( TODAY() ) - 2, 1, 1 ), DATE ( YEAR ( TODAY() ) + 1, 12, 31 ) ),
"Year", YEAR ( [Date] ),
"MonthNumber", MONTH ( [Date] ),
"MonthName", FORMAT ( [Date], "MMM" ),
"YearMonth", FORMAT ( [Date], "YYYY-MM" ),
"WeekStart", [Date] - WEEKDAY ( [Date], 2 ) + 1,
"WeekEnd", [Date] - WEEKDAY ( [Date], 2 ) + 7,
"IsCurrentWeek", IF ( [Date] >= STARTOFWEEK ( TODAY(), 2 ) && [Date] <= ENDOFWEEK ( TODAY(), 2 ), TRUE (), FALSE () ),
"IsCurrentMonth", YEAR ( [Date] ) = YEAR ( TODAY() ) && MONTH ( [Date] ) = MONTH ( TODAY() ),
"IsCurrentQuarter", YEAR ( [Date] ) = YEAR ( TODAY() ) && QUARTER ( [Date] ) = QUARTER ( TODAY() ),
"IsCurrentYear", YEAR ( [Date] ) = YEAR ( TODAY() )
)
This gives you calendar intelligence without relying on Auto Date/Time (which is better disabled for anything beyond a toy model).
The CMO doesn’t care about impressions or click-through rate in the Monday dashboard. They care about:
All measures below assume:
FactSpend[SpendAmount] is numeric currencyFactLeads[LeadId] is unique per leadFactLeads[Stage] contains values like "Lead", "MQL", "SQL"FactOpportunities[OpportunityId] is unique per opportunityFactOpportunities[Amount] is numeric currencyTotal Spend =
SUM ( FactSpend[SpendAmount] )
Leads =
DISTINCTCOUNT ( FactLeads[LeadId] )
MQLs =
CALCULATE (
DISTINCTCOUNT ( FactLeads[LeadId] ),
FactLeads[Stage] = "MQL"
)
SQLs =
CALCULATE (
DISTINCTCOUNT ( FactLeads[LeadId] ),
FactLeads[Stage] = "SQL"
)
Opportunities =
DISTINCTCOUNT ( FactOpportunities[OpportunityId] )
Revenue =
SUM ( FactOpportunities[Amount] )
Use DISTINCTCOUNT on identifiers to avoid double-counting when a lead or opportunity appears in multiple rows (e.g., status changes).
Guard against divide-by-zero with DIVIDE:
Cost per Lead =
DIVIDE ( [Total Spend], [Leads] )
Cost per MQL =
DIVIDE ( [Total Spend], [MQLs] )
Cost per Opportunity =
DIVIDE ( [Total Spend], [Opportunities] )
Lead to MQL % =
DIVIDE ( [MQLs], [Leads] )
MQL to SQL % =
DIVIDE ( [SQLs], [MQLs] )
SQL to Opportunity % =
DIVIDE ( [Opportunities], [SQLs] )
Opportunity Win Rate % =
DIVIDE (
CALCULATE (
DISTINCTCOUNT ( FactOpportunities[OpportunityId] ),
FactOpportunities[Stage] = "Closed Won"
),
[Opportunities]
)
ROI =
DIVIDE ( [Revenue] - [Total Spend], [Total Spend] )
These measures will behave correctly under filter context (channel, campaign, region, segment) as long as your relationships are set up as above.
Monday conversations are about last week and month-to-date. You can support that with measures that use DimDate flags or standard time intelligence.
Assuming the DimDate table above and that DimDate[IsCurrentWeek] and DimDate[IsCurrentMonth] are booleans:
Spend Last Week =
VAR CurrentWeekStart = STARTOFWEEK ( TODAY(), 2 )
VAR PreviousWeekStart = CurrentWeekStart - 7
VAR PreviousWeekEnd = CurrentWeekStart - 1
RETURN
CALCULATE (
[Total Spend],
FILTER (
DimDate,
DimDate[Date] >= PreviousWeekStart && DimDate[Date] <= PreviousWeekEnd
)
)
Spend MTD =
CALCULATE (
[Total Spend],
DimDate[IsCurrentMonth] = TRUE ()
)
Leads Last Week =
VAR CurrentWeekStart = STARTOFWEEK ( TODAY(), 2 )
VAR PreviousWeekStart = CurrentWeekStart - 7
VAR PreviousWeekEnd = CurrentWeekStart - 1
RETURN
CALCULATE (
[Leads],
FILTER (
DimDate,
DimDate[Date] >= PreviousWeekStart && DimDate[Date] <= PreviousWeekEnd
)
)
Revenue MTD =
CALCULATE (
[Revenue],
DimDate[IsCurrentMonth] = TRUE ()
)
Using explicit date filters like this keeps the logic transparent when the CMO asks "what exactly does 'last week' mean?" (here: Monday–Sunday, using STARTOFWEEK with Monday as day 2).
If your organization prefers calendar weeks or fiscal periods, adjust the DimDate table with those flags and keep the measures referencing those columns.
Once the model and measures are solid, the dashboard layout is straightforward. One page, three zones:
Across the top:
Use card visuals bound to the measures we defined. Keep formatting consistent:
Two key visuals:
Channel performance matrix
DimChannel[ChannelName][Total Spend], [Leads], [MQLs], [Opportunities], [Revenue], [Cost per Lead], [ROI]Campaign performance table
DimCampaign[CampaignName][Cost per Lead] and [ROI] to highlight outliersThese visuals let the CMO quickly see which channels and campaigns are driving efficient pipeline.
CMOs care about trajectory, not just snapshots. Add:
DimDate[Date] on axis, [Revenue] as values, filtered to the current quarterExample target measure (hard-coded for illustration; in practice, drive this from a table so marketing ops can adjust without changing DAX):
Quarter Pipeline Target =
VAR CurrentQuarter = QUARTER ( TODAY() )
VAR CurrentYear = YEAR ( TODAY() )
RETURN
SWITCH (
TRUE (),
CurrentYear = YEAR ( TODAY() ) && CurrentQuarter = QUARTER ( TODAY() ), 500000,
BLANK ()
)
Bind [Quarter Pipeline Target] as a constant line in the line chart. In production, use a dimension table like DimTargets and a measure that looks up the appropriate target based on Year and Quarter from DimDate.
The hardest part for marketing analysts is matching spend to leads and opportunities in a way that stands up to scrutiny.
In this scenario, you’re not building a full multi-touch attribution model; you’re building reasonable primary-touch attribution that the CMO can understand.
Make sure DimCampaign can join to all sources:
In Power Query, standardize campaign IDs/names before loading to the model:
let
Source = Excel.Workbook ( File.Contents ( "CampaignMap.xlsx" ), null, true ),
CampaignSheet = Source{[Item="CampaignMap",Kind="Sheet"]}[Data],
PromotedHeaders = Table.PromoteHeaders ( CampaignSheet, [PromoteAllScalars=true] ),
TrimmedNames = Table.TransformColumns (
PromotedHeaders,
{{"CampaignName", Text.Trim, type text}}
),
UppercaseIds = Table.TransformColumns (
TrimmedNames,
{{"PlatformCampaignId", Text.Upper, type text}}
)
in
UppercaseIds
Load that as DimCampaign, then map keys in each fact table to DimCampaign[CampaignKey] in Power Query. This avoids brittle string joins in DAX.
For a simple, defensible approach:
FactLeads[PrimaryCampaignKey]Then in DAX, you can safely slice leads and opportunities by DimCampaign without complex attribution logic.
If your CRM tracks campaign influence on opportunities, you can extend the model later. For the Monday dashboard, keep it simple and transparent.
Marketing datasets in Chicago businesses often grow fast: more platforms, more campaigns, more history. A few guardrails keep your CMO dashboard responsive.
For a weekly CMO dashboard with data volumes typical of marketing (hundreds of thousands to a few million rows per fact table), Import mode is usually appropriate:
If you connect to large cloud warehouses or need near-real-time data, you may consider DirectQuery or composite models, but that introduces latency and query limits. For a Monday dashboard where data can be refreshed overnight, Import is simpler and faster.
For this use case:
When configuring incremental refresh for a fact table like FactLeads:
Date column used in the policyIf the dashboard will be used by regional leaders in addition to the CMO:
DimRegion)For the CMO, you’ll typically grant access to all data, but RLS still matters for broader distribution.
Once the dashboard is built and validated:
For executives, consider:
Make sure the CMO understands that numbers in the email snapshot are point-in-time; if they open the report later in the day after a refresh, values may differ.
Before you add another visual to your marketing report, sketch the Spend → Leads → Opportunities → Revenue chain and define the minimum tables and measures you need to represent it cleanly; once that model is solid, the Power BI dashboard your CMO opens every Monday becomes a single, trusted view instead of a weekly debate about whose numbers are right.
This article reflects how marketing data teams are standardizing Power BI models around a simple spend-to-revenue funnel so CMOs and regional leaders can rely on one Monday dashboard instead of juggling multiple conflicting reports.
Professionals who want to apply these patterns to their own data can explore Excelgoodies' Power BI Training in Chicago, Illinois programme - taught live by instructors, with certification awarded once a real project is running at work.
Insights compiled through ongoing industry research and discussions within the Excelgoodies Analytics Community.
Power BI
New
Next Batches Now Live
Power BI
SQL
Power Apps
Power Automate
Microsoft Fabrics
Azure Data Engineering