Courses Learn Blog Contact
Get Started →
Lesson 10

Day 8: Calculated Columns vs Measures and DAX Basics

Row context and filter context, SUM, SUMX, COUNTROWS, DIVIDE and the rules for writing measures.

Webbo3 Power BI Cohort 1 11 min read Free

Webbo3 Power BI · Cohort 1 · Day 8 of 16

Day 8: Calculated Columns vs Measures and DAX Basics

The formula language of Power BI, and the one decision that confuses everybody: column or measure?

By the end of today you can

  • Say what DAX is and where you type it
  • Tell row context from filter context
  • Choose between a calculated column and a measure
  • Write measures with SUM, COUNTROWS, DISTINCTCOUNT, AVERAGE and DIVIDE
  • Use an iterator (SUMX) and RELATED, and know when you need them
  • Name, format and organise measures properly

Power Query shaped the data. DAX is how you ask it questions: how much, how many, how fast, compared with what.

Today every formula is typed in the report, not in Power Query. Open your Day 7 file with the star schema and the Date table in place.

1. What DAX Is

Definition

DAX (Data Analysis Expressions) is the formula language of the Power BI model. It looks like Excel formulas, but it works on whole tables and columns, not on cells. You type it in the formula bar after choosing New measure or New column.

Real-Life Example

Excel is a calculator you point at one cell at a time. DAX is asking the accountant a question: "total revenue", and she knows to add up only the rows for the station, month or product you are currently looking at.

Types: The Three Things You Can Write in DAX

WhatWhereStored?Example
MeasureModeling, New measureNo: calculated when a visual asksTotal Revenue
Calculated columnModeling, New columnYes: one value per row, saved in the tableSales[Region]
Calculated tableModeling, New tableYesThe Date table from Day 7

Reading a Formula

Every DAX formula starts with a name, then =, then the expression. Columns are written TableName[ColumnName], and a table name with spaces goes in single quotes: 'Sales Clean'[TotalAmount_NGN]. Measures are written in square brackets alone: [Total Revenue]. That difference tells you at a glance which is which.

Picture This

Picture the accountant who adds up only the pile in front of her. Move a different pile in front of her and she adds that one.

2. Row Context and Filter Context

Definition

Row context means "this row": a formula that can see one row at a time and use its values. Calculated columns have it. Filter context means "these rows": the set of rows left after every filter currently applied (the visual's rows and columns, slicers, the filter pane). Measures are calculated in it.

Real-Life Example

A pump attendant filling one car is in row context: this car, these litres, this price. The station manager reading the day's total is in filter context: all the cars at this station, today. Same data, a different question.

Row contextFilter context
QuestionWhat is the value for this row?What is the total for these rows?
Who has itCalculated columns, and iterators like SUMXMeasures
Changes whenNever, once the table is refreshedEvery time the reader clicks or filters
Picture This

Picture the attendant with one car, and the manager with the whole day's total.

3. Calculated Columns

Definition

A calculated column adds a column to a table, worked out row by row with row context, and saves every value in the model. Use one when you need the value to slice or group by, not to add up.

Real-Life Example

Writing on each receipt whether the quantity is in litres or in units, so nobody adds five litres of diesel to five tins of grease. The unit is a label on the row, not a total.

RELATED(Table[Column]) follows a relationship from the many side to the one side and fetches the value for this row. It only works in row context and only along a relationship.

Click path

1.Table view › Sales › Table tools › New column
What this code doesWe want each sale labelled with its product's unit, litres or units, fetched through the Product_Master relationship.
New column
1
2
// Fetch the unit of measure of the product sold on this row
Unit = RELATED ( Product_Master[UnitOfMeasure] )
Table view: Sales
ABCTransactionIDABCProductName1.2QuantityABCUnit
1TXN-2023-000383PMS (Petrol)9.7Litres
2TXN-2023-002468Engine Oil2Units
3TXN-2023-002161PMS (Petrol)39.7Litres
4TXN-2023-002789PMS (Petrol)41Litres
5TXN-2023-001103PMS (Petrol)36.1Litres
6TXN-2023-001142Grease3Units
7TXN-2023-002139PMS (Petrol)44.5Litres
8TXN-2023-003101Grease3Units
4 COLUMNS, 6,181 ROWS · first 8 shown

Prefer Power Query for Columns

The same Unit could have been merged in Power Query on Day 5, just as City, Region and Category were. The rule most professionals follow: if a column can be made in Power Query, make it there (it is compressed better and kept with the rest of the cleaning). Use DAX columns when you need the model, such as RELATED.

The Classic Mistake: A Total in a Column

What this code doesWe want to see what happens when a total-style formula is written as a calculated column instead of a measure.
New column
1
2
// WRONG: a calculated column that tries to hold an average
Avg Sale Column = AVERAGE ( Sales[TotalAmount_NGN] )
Table view: Sales
ABCTransactionIDABCStationName1.2TotalAmount_NGN1.2Avg Sale Column
1TXN-2023-000383Bodija Filling Station1,817.7823,597.19
2TXN-2023-002468Bodija Filling Station6,805.7423,597.19
3TXN-2023-002161Bodija Filling Station24,320.6223,597.19
4TXN-2023-002789GRA Filling Station26,175.2223,597.19
5TXN-2023-001103Wuse Filling Station6,486.4523,597.19
6TXN-2023-001142Independence Layout Filling Station3,607.223,597.19
7TXN-2023-002139Bodija Filling Station28,031.8823,597.19
8TXN-2023-003101Sabon Gari Filling Station3,645.0923,597.19
4 COLUMNS, 6,181 ROWS · first 8 shown

Every row holds the same number, ₦23,597.19, the average of the whole table, frozen at refresh. It will never change when the reader filters to Lekki or to 2024. Averages and totals belong in measures.

Picture This

Picture "litres" or "units" written on each receipt: a label you sort by, not a sum.

4. Measures

Definition

A measure is a named calculation that is worked out when a visual needs it, in the filter context of that visual. It is not stored per row. The same measure gives the grand total on a card, and a separate answer for each row of a table.

Real-Life Example

"Total offering" is a measure. Ask it for the whole church and it gives the whole church. Ask it for the youth service and it gives the youth service. You do not write a new formula for each; the question sets the context.

Types: The Aggregation Functions

FunctionReturnsExample
SUM(col)The total of a number columnTotal revenue
AVERAGE(col)The mean of a number columnAverage revenue per sale
COUNTROWS(table)How many rowsNumber of sales
DISTINCTCOUNT(col)How many different valuesAttendants who made a sale
MIN(col), MAX(col)Smallest and largestFirst and last sale date
DIVIDE(a, b)a divided by b, or blank if b is zeroAverage sale, safely

Keep measures in one place

1.Home › Enter Data › Name the table _Measures › Load
2.Select _Measures › Table tools › New measure

A table called _Measures (with an underscore so it sorts to the top) is a common way to keep every measure in one place instead of scattered across tables.

What this code doesWe want a measure for total revenue, and to see it on a card with no filters: both years, every station.
Measure
1
2
// The sum of TotalAmount_NGN over whatever rows are in the current filter
Total Revenue = SUM ( Sales[TotalAmount_NGN] )
Card visual
₦145.9M
Total Revenue
₦145,854,226
What this code doesWe want the number of sales, counted as rows of the Sales table.
Measure
1
2
// How many sales rows are in the current filter
Transactions = COUNTROWS ( Sales )
Card visual
6,181
Transactions
What this code doesWe want to count how many different attendant names appear on at least one sale.
Measure
1
2
// How many different attendant names appear in the current filter
Attendants Selling = DISTINCTCOUNT ( Sales[AttendantName] )
Card visual
18
Attendants Selling

18 is 17 people plus "Unmanned", which DISTINCTCOUNT counts as one more name. Knowing exactly what a measure counts is half of writing it: on Day 10 you will learn to leave Unmanned out.

What this code doesWe want the average revenue per sale, built from the two measures above, safe when there are none.
Measure
1
2
// Revenue per sale; DIVIDE returns blank instead of an error if there are no sales
Average Sale = DIVIDE ( [Total Revenue], [Transactions] )
Card visual
₦23,597.19
Average Sale

Notice that Average Sale is built from other measures, written in square brackets. Measures reuse measures: define Total Revenue once and every later measure builds on it. DIVIDE is safer than /: filter to a station with no sales and / gives an error, while DIVIDE gives a blank.

Filter Context at Work

What this visual showsWe want the same three measures in a table visual with PaymentMethod as the rows. Nothing about the measures changes; each row just filters Sales to one payment method first.
Table visual
PaymentMethodTotal RevenueTransactionsAverage Sale
Cash₦49,199,6322,103₦23,394.97
POS₦47,478,4962,019₦23,515.85
Transfer₦49,176,0982,059₦23,883.49
Total₦145,854,2266,181₦23,597.19

The total row is not the sum of the averages above it. It is the measure calculated again with no payment filter. Measures always recalculate for the total; they never just add up the rows.

Picture This

Picture the offering count: the same question, "how much?", answered for whichever service you point at.

5. Iterators: SUMX

Definition

An iterator is a function that goes through a table row by row (creating row context), works out an expression for each row, then aggregates the results. SUMX(table, expression) sums them; AVERAGEX, MAXX and COUNTX do the same with other aggregations.

Real-Life Example

A cashier at closing time who goes through every receipt, multiplies quantity by price on each, and adds the answers. No total column needed: the multiplication happens as she goes.

What this code doesWe want revenue calculated straight from Quantity and UnitPrice_NGN, row by row, without relying on TotalAmount_NGN, and to check it matches Total Revenue.
Measure
1
2
3
4
5
6
// For each sale: quantity times price. Then add all of those up.
Revenue (SUMX) =
SUMX (
    Sales,
    Sales[Quantity] * Sales[UnitPrice_NGN]
)
Two cards side by side
₦145.9M
Revenue (SUMX)
₦145,854,226
₦145.9M
Total Revenue
₦145,854,226
SUM(Quantity) * SUM(UnitPrice_NGN) Is Not Revenue

Multiplying two totals gives total litres times the sum of every price, a meaningless huge number. When the calculation must happen per row before adding, you need an iterator.

Picture This

Picture the closing cashier: multiply on every receipt, then add.

6. Naming and Formatting Measures

  • Names a manager would say: Total Revenue, not SumRev1.
  • Format as you create: select the measure, Measure tools, Format. For naira, choose Currency, or type a custom format ₦#,0.
  • Build on measures: Average Sale uses [Total Revenue]; if the definition of revenue changes, you change one measure.
  • Comment long formulas with //, as the examples above do.

Do This Now

  1. Create a _Measures table.
  2. Write Total Revenue, Transactions, Attendants Selling and Average Sale, and format each.
  3. Add a Unit calculated column with RELATED.
  4. Build the PaymentMethod table visual and read the total row.
  5. Write Revenue (SUMX) and check it equals Total Revenue.
  6. Write the wrong Avg Sale Column, see the same number on every row, then delete it.

Checkpoint

Q1. Calculated column or measure: the total revenue for whatever the reader has selected?

A measure. It must change with every filter; a column is fixed per row at refresh.

Q2. Calculated column or measure: a label to group sales by region?

A column (or better, use the Station_Master[Region] column through the relationship). It is a label per row, not a total.

Q3. Why is the total row of a table visual not the sum of its rows for Average Sale?

Measures recalculate for the total with the row filter removed: total revenue divided by total transactions, not the sum of the averages.

Q4. When do you need SUMX instead of SUM?

When something must be worked out on each row before adding, such as quantity times price.

Tick Before You Move On

  • ☐ Total Revenue shows ₦145,854,226 on a card
  • ☐ Transactions shows 6,181
  • ☐ Average Sale uses DIVIDE and other measures
  • ☐ I can say in one sentence what row context and filter context are
  • ☐ My measures live in a _Measures table and are formatted

Quick Recap

DAX is written in the model: measures, calculated columns and tables. Row context is one row; filter context is the set of rows a visual is looking at. Columns are labels per row; measures are totals that follow the filters. DIVIDE is safe division; measures build on measures. Use an iterator like SUMX when each row must be calculated before adding.

Final Scenario

The manager asks: "What is our average sale, and is it different for POS customers?"

One measure answers both. On a card it says ₦23,597.19. In the payment table, each row gives its own average, and the total row gives the true overall figure, not an average of averages.

Write it once; let the filters ask the questions.

Next, Day 9 Lab: relationships in Model view and your first page of measures, built and checked together. Assignment 2 is released.

Learn this with a real instructor

Free lessons take you a long way on your own. The full programmes add live classes, assignments, Skill Points and a certificate — built for African students.