From messy files to a published dashboard.
You don't learn Power BI by reading. You learn it by cleaning ugly data, wiring up a model, writing measures, and shipping a dashboard people actually use. This course walks that whole path on one realistic dataset, and explains the why behind every step.
What you'll build, the capstone Sales Performance dashboard, from the raw files in this course.
Three tracks, one path
This is a mixed-level course. Follow the main path top to bottom; watch for these boxes so nobody's bored or lost.
The deeper, "professional" way. Skip on a first pass, come back for it.
The Excel skill you already have, and its Power BI equivalent.
How to know you got it right before moving on.
The data pack
All files live in data/raw/. Every messy thing in them is deliberate, each
flaw teaches a specific skill.
| File | Type | Role | Teaches |
|---|---|---|---|
Sales_Raw.csv | CSV | Main fact table (~1,500 orders) | Importing + cleaning nearly everything |
Reps.csv | CSV | Sales reps dimension | Relationships, the why relate lesson |
Products.xlsx | Excel | Product dimension | Connecting to an emailed workbook |
Targets_Wide.csv | CSV | Monthly targets (months as columns) | Unpivot & % of target |
Employees_Raw.csv | CSV | HR headcount | Grouping many orgs into HR vs Other |
Sales_December_2025.xlsx | Excel | A "later" emailed monthly file | Append / refresh, static vs dynamic |
Open Sales_Raw.csv in Notepad (not Excel, which silently "fixes" things and hides the
mess). Notice dates as 2024-03-15, 3/15/2024, 15-Mar-2024, and blanks;
Region as North, north, EAST, S., Norht, and " North "
with spaces; UnitPrice as $1,518.50. This is what real exported data looks like.
Never trust a column is clean until you've proven it.
Download the data pack
Everything you need for the hands-on lessons and the capstone. Each file is deliberately messy, the flaws are the curriculum. Open the CSVs in Notepad (not Excel) to see the mess before you fix it in Power Query.
Sales_Raw.csv
Main fact table, ~1,500 messy orders
Download ↓CSV · 1 KBReps.csv
Reps dimension, the RepID link
Download ↓XLSX · 6 KBProducts.xlsx
Product dimension (emailed Excel)
Download ↓CSV · 1 KBTargets_Wide.csv
Monthly targets, months as columns
Download ↓CSV · 6 KBEmployees_Raw.csv
HR headcount. HR vs Other grouping
Download ↓XLSX · 10 KBSales_December_2025.xlsx
A later emailed month, append/refresh
Download ↓CSV · 92 KBSales_Solution_Clean.csv
Clean 'solution' Sales table, check your work
Download ↓CSV · 23 KBSupport_Tickets_Raw.csv
Mini-project 2, messy support tickets
Download ↓CSV · 2 KBCustomers.csv
Customers dimension for the mini-project
Download ↓CSV · keyOrg_Grouping_Key.csv
HR/Other mapping table (Method C)
Download ↓Instructor & extra resources
For anyone teaching or running this as a workshop.
Setup, the interface & how licensing actually works
Install the tool, learn the map of the screen, and understand the license landscape before you build, because the license you have changes how you publish later.
Install Power BI Desktop (free)
Power BI Desktop is where you build, and it's free.
- Best on Windows: Microsoft Store → search "Power BI Desktop" → Install. The Store version auto-updates monthly, which matters. Power BI ships features every month.
- Alternative: download the installer from
powerbi.microsoft.com. - On a Mac? No native version. You'll need Windows via a VM (Parallels) or a cloud PC. The browser Service lets you view, not fully build.
The three views + one door
- Report view (chart icon), build visuals and the dashboard.
- Data view (grid icon), inspect the actual loaded rows.
- Model view (relationship icon), see tables and the lines between them.
- Transform data (Home ribbon), opens the Power Query Editor, the cleaning room.
Power Query = Get & Transform in Excel (same engine). The data model = the Data Model behind PivotTables (Power Pivot). Report view = a far more powerful version of charts on a sheet. If you've used Get & Transform, you already know ~40% of this.
Licensing, the 3-minute version
- Desktop, free, build anything locally.
- Free account (Service), publish to your own My Workspace; generally can't share.
- Pro, publish to shared workspaces and share reports (viewers also need Pro, unless the workspace is on Premium).
- Premium Per User (PPU). Pro plus bigger/faster features.
- Premium / Fabric capacity, org buys capacity; then viewers can be free. How big companies share widely.
Module 8 turns this into a decision tree.
Getting data, and the emailed-file problem
Connect to files the right way, and learn the single most important sharing concept: static vs. dynamic connections.
Connect to the main file (CSV)
- Home → Get data → Text/CSV → pick
Sales_Raw.csv→ Open. - A preview appears. Power BI guesses types, and will guess wrong on this messy file. Expected.
- Do NOT click Load. Click Transform Data.
Clicking Load and dealing with the mess later inside the report. Always click Transform Data first and clean in Power Query. Loading dirty data means broken visuals and wrong numbers downstream.
Static vs. dynamic: the concept that separates amateurs from pros
When you connect to a file, where that file lives determines whether your report can refresh by itself.
Static (fragile): you connect to a path only your machine can see, C:\Users\you\Downloads\Sales_Raw.csv. When you publish to the cloud, the cloud can't reach
your Downloads. To update, you open Desktop, re-import, and re-publish by hand every time.
Dynamic (robust): you connect to a place the cloud can also reach, OneDrive for Business, SharePoint, a gateway'd network path, or a database. Now you can schedule automatic refresh: the report re-reads the source on a timer, no human needed.
Why the file's location decides everything
So when a colleague emails you Sales_Report.xlsx every Monday, you have three tiers:
| Approach | How | Auto-refresh? |
|---|---|---|
| Save to Downloads, import | Get data → local path | No |
| Save to synced OneDrive/SharePoint, import from there | Get data → SharePoint/OneDrive | Yes |
| Sender drops into a fixed folder, connect to the folder | Get data → Folder connector | Yes ++ |
Connect to a folder instead of one file (Get data → More → Folder). Power Query combines
every file matching the shape. Next month, the sender drops Sales_February.xlsx in →
you hit Refresh → February appears. No re-import, no editing queries.
This is the answer to "the data gets emailed to me every month." We use it in Module 3.
Outlook attachments live inside the email, not on disk. Power BI can't read a mailbox as a normal user. The workflow is always: attachment → saved to a cloud-synced folder → Power BI reads the folder. Automating the save step is a job for Power Automate (Stretch topic).
Connect to the emailed Excel dimension
- Get data → Excel workbook →
Products.xlsx→ Open. - In the Navigator, tick the
Productssheet/table. - Transform Data (again, always).
If the sender formatted their data as a proper Excel Table (Ctrl+T), connecting is rock-solid. If it's just cells, you connect to the sheet's used range, fragile if they add notes or blank rows. Coach your data senders to use real Tables; it's the biggest gift they can give you.
You can explain in one sentence why saving an emailed file to Downloads makes a published report go stale, the cloud can't reach your Downloads, so scheduled refresh has nothing to read.
Power Query: fixing bad data
Turn Sales_Raw.csv from garbage into a trustworthy table. This is where
70% of real Power BI work happens, and where beginners under-invest.
The Applied Steps pane records every change as replayable instructions that re-run on every refresh. You're not cleaning data, you're writing a repeatable recipe that fixes next month's file automatically too.
The same rows, before & after Power Query
Fix data types (the #1 source of wrong numbers)
- OrderDate: text (mixed formats). Change type → Date. Ambiguous US/UK dates? Right-click →
Change Type → Using Locale → English (United States). Blanks become
null, correct. - UnitPrice (
$1,518.50): Replace$→ nothing, replace,→ nothing, then change type → Decimal. - Units (
1,200,N/A): replace,; convert to Whole Number; then Replace Errors withnull(a bad count is unknown, not zero).
Delete the auto "Changed Type" step, do text cleanup first, then add one Changed Type step near the end. Stray multiple type steps are a top cause of refresh errors when next month's values differ.
Trim & clean whitespace (the invisible bug)
" North " and " Enterprise " look identical to North but are different
values, they'll split your totals into two bars. Select the columns → Transform →
Format → Trim, then Format → Clean.
Untrimmed text is the #1 cause of "why do I have two 'North' bars?" It's invisible in the data but real to the engine. Trim early, trim always.
Standardize typos & abbreviations
Region still has north, EAST, S., Norht. Quick fix: Replace Values,
one per variant. Brittle, a new typo next month slips through.
Build a small map (Variant → CleanRegion), Merge it in, pull the clean value.
New variants get added to the map, not the query logic. Same idea powers the HR grouping in Module 3.
Remove duplicate rows & handle Discount
- Select all columns → Home → Remove Rows → Remove Duplicates (removes the ~20 exact-duplicate orders).
Discountmixes blank /0/10%/0.1. Replace blanks with0; convert10%text to0.10via a custom column (if Text.Contains([Discount],"%") then …).
Removing duplicates on all columns removes truly identical rows (safe). On one column it's a different, aggressive operation. For a fact table, only remove fully identical rows.
OrderDate is a real Date; UnitPrice and Units are numbers; Region/Segment
have no stray spaces or typos; duplicates are gone. Your Applied Steps read like a clean recipe.
Reshaping data into something meaningful
The moves that turn "technically clean" into "actually useful", including your exact ask: collapse many organizations into HR vs Other.
Add revenue, duplicate columns, extract parts
- Custom Column
LineRevenue = [Units] * [UnitPrice] * (1 - [Discount]). - Duplicate Column (right-click) when you need the same source shaped two ways, keep the original and a grouped/extracted version. This sets up the HR grouping below.
- Column From Examples, type the output you want for a few rows; Power Query writes the logic.
Compute per-row values you'll filter on as columns; compute filter-aware aggregations (totals, YoY) as measures. Row-level revenue is a fair column; "Total Revenue" will be a measure. When in doubt, measure, columns bloat the model.
★ Grouping many categories into few: HR vs Other
Collapse ~22 organizations into two meaningful buckets
Organization, then a Conditional Column (or a mapping-table merge) sorts every value into HR or Other, you keep the detail and gain the summary.Employees_Raw.csv's Organization column has ~22 values (Human Resources, HR,
People & Culture, Talent Acquisition, Recruiting, Learning & Development,
HR Operations, People Ops, plus Finance, Engineering, IT…). You want just
HR vs Other.
Step 1, duplicate Organization → rename the copy OrgGroup (keep the detail).
Step 2, collapse it. Three methods, worst → best:
- A · Replace Values, map each HR variant to
HR. Awkward to turn "everything else" intoOther. - B · Conditional Column (recommended). Add Column → Conditional Column: If
Organizationequals each HR variant ThenHR; ElseOther. Reads like plain English and is easy to extend. Trim/Clean first soequalsmatches. - C · Mapping table (scales to 200 categories), a two-column lookup
(
Organization → OrgGroup, shipped atdata/reference/Org_Grouping_Key.csv), then Merge Queries onOrganizationand expandOrgGroup. Grouping logic lives in a spreadsheet a business user can edit, no query surgery when a new department appears.
Method A ≈ nested IF/SUBSTITUTE; Method B ≈ IFS; Method C ≈ XLOOKUP against a mapping
tab. Same logic you already use, made repeatable.
Employees has both Organization (detailed) and OrgGroup (HR / Other only).
You kept the detail and gained the summary, that's why we duplicated the column.
Unpivot: fix "months as columns"
Targets_Wide.csv has Team then one column per month. Power BI wants long data:
one row per Team per Month. Select Team → right-click → Unpivot Other Columns. Rename
Attribute → MonthLabel, Value → Target; convert MonthLabel to a real date.
Wide → long: what "unpivot" actually does
Wide data can't be sliced, can't relate to a date table, and breaks when a new month is added. When a table has dates or categories running across the top, your instinct should be "unpivot."
Append the "next month" emailed file
Sales_December_2025.xlsx just arrived. Manual way: Append Queries. Dynamic way: the
Folder connector from Module 1, drop next month's file in the folder, hit Refresh, done.
Append needs matching columns/types, exactly why we cleaned types deliberately in Module 2. Then Home →
Close & Apply.
The data model & relationships, the "why"
Understand why you split data across tables and connect them, the concept that makes everything after it possible.
The problem relationships solve
Sales has RepID = 1017. That number is meaningless alone, who is 1017? What
team? When hired? That lives in Reps. A relationship tells Power BI "the RepID in
Sales points to the RepID in Reps." Now every order silently knows its rep's name, team, and region, and you can slice sales by team even though Sales has no team column.
This is XLOOKUP, but set up once, at the table level, instead of dragging a
formula down a million rows. Keep one clean Reps list and link to it. That link is a relationship.
Why not one big table?
Jamming rep name, product, category onto every order, a "flat" table, causes bloat & slowness (names repeat on thousands of rows), inconsistency (same rep spelled two ways), and rigidity (no clean list of all reps, only those who sold). The pro shape is a star schema: one fact table (events + keys + numbers) surrounded by dimension tables (the descriptions you filter by).
Create relationships
Model view → drag Sales[RepID] onto Reps[RepID]; drag Sales[ProductID] onto
Products[ProductID]. Double-click a line to inspect:
- Cardinality: Many-to-one (∗:1), many sales to one rep. The healthy default.
- Cross-filter direction: Single (the "1" side filters the "many"). Leave it single unless you have a reason.
We planted RepID 9999, a rep not in Reps. Those orders still count but show under a
blank rep. That blank is Power BI telling you your data has an orphan key. Real skill:
noticing it and asking "why is there a sale from a rep we don't have on file?"
Build a proper Date table (do not skip)
Time intelligence (YoY, YTD, running totals) needs a dedicated Date dimension, one row per day, related to
Sales[OrderDate].
Date =
ADDCOLUMNS(
CALENDAR(DATE(2024,1,1), DATE(2025,12,31)),
"Year", YEAR([Date]),
"MonthNo", MONTH([Date]),
"Month", FORMAT([Date],"MMM"),
"MonthYear", FORMAT([Date],"MMM yyyy"),
"Quarter", "Q" & FORMAT([Date],"Q")
)
Sort Month by MonthNo; relate Date[Date] → Sales[OrderDate]; then Table tools →
Mark as Date Table.
Slicing by Sales[OrderDate] only shows dates that had a sale, and can't compare against
Targets (different dates). A shared Date dimension relates to both, so one slicer filters everything,
and SAMEPERIODLASTYEAR/DATESYTD require a marked date table. This one habit prevents a
whole class of "my YoY is wrong" bugs.
Model view shows a star: Sales in the middle, lines to Reps, Products, Date. Every
line many-to-one, single direction. No table stranded. You can say out loud why each line exists.
Measures & DAX
Write calculations that respond to whatever the user filters. This is where a report becomes intelligent.
Measure vs. calculated column
A column is computed once per row at refresh, and stored (use for row attributes you filter by). A measure is computed on the fly for the current filter context (use for all aggregations).
Beginners make everything a column because it feels like Excel. Columns bloat the model. Default to measures for anything you'd sum, average, or compare. If I'm aggregating, it's a measure.
Core measures, build in order
Total Revenue = SUM ( Sales[LineRevenue] )
Total Units = SUM ( Sales[Units] )
Order Count = DISTINCTCOUNT ( Sales[OrderID] )
Avg Order Value = DIVIDE ( [Total Revenue], [Order Count] )
Use DIVIDE, never /, it handles divide-by-zero gracefully (returns blank, not an error).
SUMX, then CALCULATE, the most important function in DAX
Total Revenue (SUMX) =
SUMX ( Sales, Sales[Units] * Sales[UnitPrice] * (1 - Sales[Discount]) )
Enterprise Revenue = CALCULATE ( [Total Revenue], Reps[Team] = "Enterprise" )
% of Region Total =
DIVIDE ( [Total Revenue], CALCULATE ( [Total Revenue], ALL ( Sales[Region] ) ) )
SUMX walks each row then sums. CALCULATE changes the filter context, add a filter, or remove
one with ALL.
Almost every "advanced" measure is CALCULATE([base], <filter change>). Understand
CALCULATE + filter context deeply and you understand DAX. Invest here.
Time intelligence & % of target
Revenue LY = CALCULATE ( [Total Revenue], SAMEPERIODLASTYEAR ( 'Date'[Date] ) )
Revenue YoY % = DIVIDE ( [Total Revenue] - [Revenue LY], [Revenue LY] )
Revenue YTD = TOTALYTD ( [Total Revenue], 'Date'[Date] )
Total Target = SUM ( Targets[Target] )
Revenue vs Target % = DIVIDE ( [Total Revenue], [Total Target] )
Drop Total Revenue, Revenue YoY %, Revenue vs Target % into a table by
Reps[Team]. Numbers change sensibly when you click a region slicer. YoY blank everywhere? Your Date
table isn't marked or related, back to Module 4.
Visualizations: how to think about them
Stop asking "what chart looks cool" and start asking "what question am I answering." Chart choice is a communication decision, not decoration.
Start from the question, then pick the visual
| The question is about… | Sounds like… | Use |
|---|---|---|
| Comparison between categories | "Which team sells most?" | Bar / Column |
| Trend over time | "How is revenue trending?" | Line / area |
| Part-to-whole | "What share is each region?" | Stacked bar; pie only for 2–4 slices |
| A single headline number | "What's total revenue?" | Card / KPI |
| Progress to a goal | "Are we hitting target?" | Gauge / KPI / bar + target line |
| Relationship of two measures | "Do bigger orders discount more?" | Scatter |
| Detail / lookup | "Show me the actual orders" | Table / Matrix |
| Geography | "Revenue by region on a map" | Map (only if geography truly matters) |
When to use what, the six workhorses
Humans can't compare angles well. Pie only for 2–4 parts summing to a meaningful whole. For "revenue by 8 products," a bar chart wins every time.
Data storytelling, what you show is the story
The same numbers can inform or mislead depending on which data you show and how you display it. That choice is the real analysis, the chart is your argument, not decoration. A dashboard that shows everything says nothing; a good one answers a decision at a glance.
Two habits carry most of it: (1) show the comparison that answers the question and cut the rest, and (2) make the takeaway readable in seconds, sort it, start value axes at zero, use one colour that means something, label directly, and write the title as the insight ("Laptop Pro drives 22%"), not the field name.
Same data, two ways, the display makes or breaks the story
Title states the takeaway, not the field. Grey out everything and colour the one bar that matters. Annotate the moment on a trend line ("new pricing launched"). Order categories by value, not alphabetically. You're not just plotting numbers, you're making a point, and removing everything that competes with it.
Build one, then format so it earns its keep
- Clustered column →
Reps[Team]on X,[Total Revenue]on Y. Add a Year slicer, it responds live. - Sort bars by value descending (the "…" menu). Sorted bars are instantly readable.
- Axis starts at zero for bar/column, truncating exaggerates differences (that's how charts lie).
- Titles as answers, not field names. Kill leftover "Sum of LineRevenue."
- Color means something (highlight the max, red/green vs target), never rainbow decoration.
Clicking a bar cross-filters every other visual (the main reason dashboards beat static reports). Add drill-down (Year→Quarter→Month) and drill-through detail pages. For every visual ask: if an exec glanced at this for 3 seconds, would they leave with the right takeaway? If not, it's decoration, cut it or fix it.
You have a sorted column chart (Revenue by Team), a line (Revenue over time), KPI cards, and clicking any bar cross-filters the rest of the page.
Assembling an impressive dashboard
Go from "a page of charts" to something designed that answers a decision. Design guides the eye to the decision fast, it isn't decoration.
Decide the story first
Write the headline before placing a visual: "How are we tracking to target this year, who's driving it, and where's the risk?" Everything on the page serves that sentence; anything else goes on a detail page.
Layout: the F-pattern & hierarchy
- Top strip: 3–5 KPI cards, the headline numbers (Revenue, YoY %, vs Target %, Orders). The "answer in 3 seconds" row.
- Upper-middle: the main trend (revenue over time vs. target), biggest real estate.
- Lower: breakdowns, by team, region, product.
- Consistent slicers (Year, Region, Team) where users expect them.
- Alignment & whitespace, snap to a grid. Aligned edges read as "designed"; ragged edges read as "amateur."
A consistent visual system
- Theme: View → Themes, define the palette once; every visual inherits it.
- Color with meaning: one accent; reserve red/green strictly for bad/good.
- Typography: one font, sized for hierarchy, big KPI numbers, medium titles, small labels.
- Bookmarks + buttons: build toggles ("By Region" vs "By Product"), a slide-in slicer panel, a reset button, page navigation.
KPI row up top · one clear main visual · everything aligned · one theme · titles tell the story · slicers
consistent · numbers formatted ($1,519, not 1518.5) · a subtitle saying what it is and when it
refreshed. Then show it to someone new, within ~10 seconds they should tell you the headline. If not, fix the
hierarchy, don't add charts.
Check color contrast (don't rely on color alone, add labels/icons), set tab order (Selection pane), and build a phone layout (View → Mobile layout).
Publishing & sharing
Get your dashboard off your laptop and into colleagues' hands, with refresh, and pick the right license path.
The mental model: Desktop → Service → Audience
You build in Desktop (a .pbix), publish to the Service
(app.powerbi.com), where reports live in workspaces. You share by granting workspace
access, or by packaging a workspace into an App.
How a report gets from your laptop to an audience
Personal vs. Pro vs. Workspace
| Destination | License | Good for / limitation |
|---|---|---|
| My Workspace (personal) | Free | Yourself only. View in browser/mobile, refresh for your own use. Generally can't share. |
| Shared Workspace | Pro (you) | Publish here, add colleagues as Admin/Member/Contributor/Viewer. Viewers need Pro unless the workspace is on Premium. |
| App | Pro + workspace | Curated, read-only package with its own navigation. How you distribute cleanly to many people. |
Which license do I actually need?
- Just me, my machine: Desktop (free).
- Just me, in the cloud/phone: free account, My Workspace.
- Share with a few colleagues: Pro for you and each viewer.
- Share widely without buying everyone Pro: Premium/Fabric capacity → viewers can be free.
- You need big models / faster refresh / paginated reports: Premium Per User (PPU).
You publish a beautiful report to My Workspace, send the link, and colleagues get "you don't have access." Fix: publish to a shared workspace (Pro), add them as Viewers, or distribute via an App. Sharing lives in workspaces, not My Workspace.
Scheduled refresh, closing the static-vs-dynamic loop
- In the Service, find your semantic model → Settings.
- Data source credentials: sign in to the source.
- Scheduled refresh: on, pick times (Pro: 8/day; Premium: 48/day).
- Only works if the source is cloud-reachable, exactly why Module 1 insisted on OneDrive/SharePoint/Folder.
On-premises Data Gateway: a small service on an always-on machine that lets the cloud reach on-prem/network data for refresh. Row-Level Security: each viewer sees only their slice. Certify shared datasets so others reuse the trusted source instead of rebuilding.
Your dashboard is in a shared workspace, colleagues can open it, scheduled refresh is green, and you can explain which license each person needs to view it.
Build & publish a "Sales Performance" dashboard
- Get data from all files; append
Sales_December_2025.xlsx(bonus: via a Folder connection). - Clean in Power Query: types, dates, currency text, whitespace, region typos, duplicates.
- Reshape:
LineRevenue; unpivot Targets; produceOrgGroup= HR vs Other. - Model: star schema with a marked Date table; relate both facts → Date; handle orphan
RepID 9999. - Measures: Revenue, Orders, AOV, YoY %, YTD, vs Target %.
- Visualize: KPI row, trend vs target, by team/category/region, sorted, formatted, cross-filtering.
- Design: one theme, aligned grid, story titles, Year/Region/Team slicers.
- Publish to a shared workspace; set scheduled refresh; note which license each viewer needs.
Grading rubric
| Area | Excellent | Pts |
|---|---|---|
| Data cleaning | Types correct; no whitespace/typos; dupes removed; errors handled | 20 |
| Reshaping | LineRevenue correct; Targets unpivoted; HR/Other clean & extensible | 15 |
| Data model | True star; marked Date table; correct cardinality; orphan handled | 20 |
| Measures | Correct, use DIVIDE, time intelligence works, % of target correct | 20 |
| Visualization | Right chart per question; sorted; formatted; sensible interactions | 15 |
| Design & polish | Hierarchy, theme, alignment, story titles; passes 10-second test | 5 |
| Publishing | Correct workspace; refresh configured; license reasoning correct | 5 |
Quick reference
Power Query cleanup
| Problem | Fix |
|---|---|
| Dates as text / mixed formats | Change Type → Date (or Using Locale) |
$1,299.00 as text | Replace $, replace , → Change Type Decimal |
N/A in a number column | Change type → Replace Errors with null |
" North " padded | Trim then Clean |
north, EAST, Norht, S. | Replace Values, or mapping table + Merge |
| Exact duplicate rows | Remove Duplicates (all columns) |
| Months as columns | Unpivot Other Columns |
| Many orgs → HR/Other | Duplicate column → Conditional Column (or mapping merge) |
| New file each month | Folder connector (auto-combine) |
DAX starter pack
Total Revenue = SUM ( Sales[LineRevenue] )
Order Count = DISTINCTCOUNT ( Sales[OrderID] )
Avg Order Value = DIVIDE ( [Total Revenue], [Order Count] )
Revenue LY = CALCULATE ( [Total Revenue], SAMEPERIODLASTYEAR ( 'Date'[Date] ) )
Revenue YoY % = DIVIDE ( [Total Revenue] - [Revenue LY], [Revenue LY] )
Revenue YTD = TOTALYTD ( [Total Revenue], 'Date'[Date] )
Total Target = SUM ( Targets[Target] )
Revenue vs Target % = DIVIDE ( [Total Revenue], [Total Target] )