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’ve built a clean sales report, your visuals look good, and your measure works perfectly for each row. Then your manager asks why the grand total doesn’t equal the sum of the rows. The numbers are correct per row, but the total row in Power BI is “wrong”.
This article walks through why that happens, using a realistic scenario, and shows how to fix it with patterns that respect how DAX really evaluates totals.
Imagine a common setup:
Sales (columns: Date, CustomerID, ProductID, Quantity, NetAmount, DiscountAmount, TargetAmount)Customers, Products, CalendarCustomer and Year, with measures for Net Sales, Target, and Achievement %You define:
Net Sales = SUM ( Sales[NetAmount] )
Target = SUM ( Sales[TargetAmount] )
Achievement % = DIVIDE ( [Net Sales], [Target] )
At the customer-year level, Achievement % looks reasonable. But the total row shows 104% while you know overall achievement should be closer to 97%. When you export to Excel and sum the visible rows, you get 103.8%, not 104%, and neither matches the “true” overall ratio.
This is the classic “Wrong Total in Power BI” problem: the total row isn’t a simple sum of the visible rows, and in many cases it shouldn’t be.
The key point: Power BI does not sum up the visible cells to compute a total row.
For a matrix or table visual:
DAX measures are always evaluated as:
Measure = expression evaluated under the current filter context
So if the measure is non-additive (like a ratio, average, or distinct count), the total row is not supposed to be the sum of the row values.
In the scenario:
Achievement % = Net Sales for that customer / Target for that customer.Achievement % = total Net Sales / total Target across all customers.Those two are mathematically different operations.
This explains the symptom:
The fix is not “make Power BI sum the rows”, but “make the measure explicit about which total behaviour you want”.
The most common cause of “wrong totals” is ratios:
These are non-additive by definition.
In our scenario:
Achievement % = DIVIDE ( [Net Sales], [Target] )
This measure:
DIVIDE( SUM(Sales[NetAmount]), SUM(Sales[TargetAmount]) ) under the total filter context.If someone expects the total to be average of customers’ Achievement % or sum of visible percentages, they’ll call it “wrong”. But mathematically, the DAX behaviour is correct for a ratio.
You can control total behaviour by explicitly defining which aggregation you want.
If the business wants overall achievement as total Net Sales / total Target, the naive measure is already correct. The “wrong total” perception comes from comparing it to a simple average of visible row percentages.
In that case:
Achievement % as is.If the requirement is to show the total as the average of the visible row percentages, you must implement that explicitly.
One reliable pattern is to compute the row-level ratio for each entity (e.g. customer) and then average those ratios at the total level.
Example where the matrix rows are Customer[CustomerName]:
Achievement % (Avg of Customers) =
VAR CustomersVisible = VALUES ( Customer[CustomerID] )
RETURN
AVERAGEX (
CustomersVisible,
VAR NetSalesCustomer = CALCULATE ( [Net Sales] )
VAR TargetCustomer = CALCULATE ( [Target] )
RETURN
DIVIDE ( NetSalesCustomer, TargetCustomer )
)
Behaviour:
VALUES(Customer[CustomerID]) returns a single value, so AVERAGEX averages one element – effectively the same as DIVIDE(NetSalesCustomer, TargetCustomer).CustomersVisible is the set of customers in the current filter context; AVERAGEX returns the average of each customer’s ratio.This now matches the “average of visible row percentages” expectation.
The logic above relies on VALUES(Customer[CustomerID]) matching the row granularity of the visual.
If the matrix rows are at another grain (e.g. Customer[Segment] instead of individual customers), adjust the measure to match that grain:
Achievement % (Avg of Segments) =
VAR SegmentsVisible = VALUES ( Customer[Segment] )
RETURN
AVERAGEX (
SegmentsVisible,
VAR NetSalesSegment = CALCULATE ( [Net Sales] )
VAR TargetSegment = CALCULATE ( [Target] )
RETURN
DIVIDE ( NetSalesSegment, TargetSegment )
)
The pattern is the same; only the grouping column changes.
Another frequent source of confusion is when a measure depends on row context (e.g. SUMX, AVERAGEX, or logic originally written for calculated columns).
You add a measure:
Sales per Active Customer =
VAR ActiveCustomers = DISTINCTCOUNT ( Customer[CustomerID] )
RETURN
DIVIDE ( [Net Sales], ActiveCustomers )
At the customer row level, ActiveCustomers = 1, so the measure just returns [Net Sales]. At a segment total, ActiveCustomers is the count of customers in that segment, so the total row shows segment sales / number of customers.
If someone expects the total row to be the sum of row-level Sales per Active Customer, they’ll see a mismatch.
For metrics like “sales per active customer”, decide what grain you care about:
Example: segment-level metric, matching total behaviour:
Sales per Active Customer (Segment) =
VAR SegmentCustomers = DISTINCTCOUNT ( Customer[CustomerID] )
RETURN
DIVIDE ( [Net Sales], SegmentCustomers )
Use this on a visual where rows are segments. Now:
If you truly need a total that sums the visible row values, you must materialise the row-level metric and then aggregate it.
Example: sum of visible row values in a matrix where rows are customers:
Sales per Active Customer (Sum of Rows) =
VAR CustomersVisible = VALUES ( Customer[CustomerID] )
RETURN
SUMX (
CustomersVisible,
VAR NetSalesCustomer = CALCULATE ( [Net Sales] )
VAR ActiveCustomersCustomer = 1
RETURN
DIVIDE ( NetSalesCustomer, ActiveCustomersCustomer )
)
Here the total row is literally the sum of row-level values.
Distinct counts and semi-additive measures (like stock levels, last non-blank) are also non-additive.
Measure:
Active Customers = DISTINCTCOUNT ( Sales[CustomerID] )
In a matrix by Product[Category]:
If a customer buys from multiple categories, they are counted once in the total.
You have two valid interpretations:
If the business needs “sum of category-level counts”, implement it explicitly:
Active Customers (Sum of Categories) =
VAR CategoriesVisible = VALUES ( Product[Category] )
RETURN
SUMX (
CategoriesVisible,
CALCULATE ( DISTINCTCOUNT ( Sales[CustomerID] ) )
)
Now the total row is the sum of the row-level distinct counts, matching the expectation, at the cost of counting the same customer multiple times if they appear in multiple categories.
Sometimes the total looks wrong because you’re not seeing all the filters that apply.
Common situations:
In our scenario, suppose there is a page filter Region = "West". A stakeholder compares the total row to a separate export that includes all regions. The numbers will differ, and the total will be blamed.
To debug, create a helper measure that shows which filters are active:
Debug Filters =
VAR Regions = CONCATENATEX ( VALUES ( Customer[Region] ), Customer[Region], ", " )
VAR Years = CONCATENATEX ( VALUES ( 'Calendar'[Year] ), 'Calendar'[Year], ", " )
RETURN
Regions & " | Years: " & Years
Place this in a card or table next to the matrix while debugging. It helps reveal unexpected filters affecting totals.
For RLS, test with View as in Power BI Desktop to see the report exactly as the stakeholder sees it.
A subtler source of confusion is when a measure references another measure that is itself non-additive.
Example:
Margin % = DIVIDE ( [Margin], [Net Sales] )
Weighted Margin % =
VAR ProductsVisible = VALUES ( Product[ProductID] )
RETURN
AVERAGEX ( ProductsVisible, [Margin %] )
At the total row, Weighted Margin % averages Margin % at the product level, not at the customer or segment level. If the matrix rows are customers, this can produce totals that look inconsistent.
Always align the granularity used inside VALUES with the visual’s row grain.
If the matrix rows are Customer[CustomerID], redefine:
Weighted Margin % (By Customer) =
VAR CustomersVisible = VALUES ( Customer[CustomerID] )
RETURN
AVERAGEX ( CustomersVisible, [Margin %] )
Now the total row is the average of customer-level margin %, which matches the matrix.
When a total row “doesn’t add up”, walk through this checklist:
Is the measure additive?
What grain is the visual using?
What is the total supposed to represent?
Which filters are active?
Are you referencing other non-additive measures?
Once you answer these, you can decide whether the total is actually wrong or just different from the expectation, and then choose the appropriate pattern.
Back to the sales performance report.
The manager wants:
Achievement % per customer-year.We implement:
Achievement % (Avg of Customers) =
VAR CustomersVisible = VALUES ( Customer[CustomerID] )
RETURN
AVERAGEX (
CustomersVisible,
VAR NetSalesCustomer = CALCULATE ( [Net Sales] )
VAR TargetCustomer = CALCULATE ( [Target] )
RETURN
DIVIDE ( NetSalesCustomer, TargetCustomer )
)
Result:
If finance later asks for a weighted overall achievement for the same matrix, we can add a second measure:
Achievement % (Weighted) = DIVIDE ( [Net Sales], [Target] )
And clearly label both in the report:
Achievement % (Avg of Customers)Achievement % (Weighted)Same data, two different total behaviours, both technically correct.
When the total row doesn’t add up, it’s almost always because DAX is doing exactly what it’s designed to do: recompute the measure under a different filter context.
The practical fix is simple but non-negotiable: design your measures with explicit total behaviour. Decide whether you want a weighted ratio, an average of row-level values, or a sum of rows, and then implement that pattern intentionally instead of relying on default aggregation.
This article reflects the growing need for Power BI teams to design measures with explicit total-row behaviour, especially in environments where non-additive KPIs like ratios and distinct counts drive high-stakes decisions.
Professionals who want to apply these patterns to their own data can explore Excelgoodies' Power BI Reporting 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