How to Get Previous Row Value in Power BI
Trying to compare a value in your current row with the value from the one right before it is a fundamental need in data analysis. Whether you’re calculating period-over-period growth, spotting trends, or tracking changes, getting that "previous value" is essential. This article walks you through the best ways to get the previous row value in Power BI using DAX, covering different situations you're likely to encounter.
Why Is Getting the "Previous Row" Hard in Power BI?
If you're coming from spreadsheets like Excel or Google Sheets, you’re used to simply referencing a cell like A2-A1. Power BI doesn't really "think" in terms of fixed, static rows in the same way. Instead, it operates on the concepts of "row context" and "filter context." Everything is dynamic.
Think of it this way:
- Excel: A static grid. Row 5 is always row 5. The row above it is always row 4.
- Power BI: A relational database engine. A visual (like a table or chart) applies filters to your data model. The data displayed is the result of those filters — sales for this month, traffic from this country. There isn't a fixed "row before." You have to use DAX to tell Power BI exactly what "before" means in the current context.
So, our goal isn't to find the "row above" but to define the context for the previous period (like last month, yesterday) or the prior item in a specific sort order.
Key DAX Functions for This Task
Before jumping into specifics, let's meet the main DAX functions we'll be using. Understanding what they do makes the formulas much easier to grasp.
- CALCULATE(): The superstar of DAX. It changes the filter context in which a calculation is performed. We'll use it to say, "calculate the total sales, but ignore the current date filter and apply one for the previous day instead."
- EARLIER(): An older DAX function primarily used in calculated columns. It lets you "escape" the current row context and get a value from an earlier, outer stage of the calculation. While it works, it can be confusing and sometimes slow.
- Time Intelligence Functions (DATEADD, PREVIOUSMONTH, etc.): A suite of functions designed specifically for time-based comparisons. They are often the easiest and most efficient way to handle date-based logic.
- Window Functions (OFFSET, INDEX): These are newer, powerful functions that are perfect for situations where you aren't dealing with dates. They let you move up or down a specified number of rows in a table, based on a sort order you define.
Free PDF · the crash course
AI Agents for Marketing Crash Course
Learn how to deploy AI marketing agents across your go-to-market — the best tools, prompts, and workflows to turn your data into autonomous execution without writing code.
Method 1: The Calculated Column Approach with EARLIER()
This is a classic method that's helpful in specific scenarios, particularly when you need to create a physical, static column in your data table. This column computes once on data refresh and doesn't change based on slicers or visuals.
Let's say you have a simple Sales table with a date and a sales amount, and you want a new column that shows the previous day's sales figure on each row.
Step 1: Create a Calculated Column
In the Data view, select your sales table and click "New Column."
Step 2: Enter the DAX Formula
Here’s the formula to find the sales from the day right before the date in the current row.
Previous Day Sales (Column) =
CALCULATE(
SUM(Sales[SalesAmount]),
FILTER(
ALL(Sales),
Sales[Date] = EARLIER(Sales[Date]) - 1
)
)Step 3: Understanding the Formula
- EARLIER(Sales[Date]): This is the key. In each row of your new column, this function grabs the
Sales[Date]value for that specific row. For instance, on the row for January 5th, this returns "January 5th". - Sales[Date] = EARLIER(Sales[Date]) - 1: This compares the date for every single row in the entire table to the date of our current row minus one day. So for the January 5th row, it finds the row where the date is January 4th.
- FILTER(ALL(Sales), ...):
FILTERcreates a small, one-row table containing only the data from the previous day. We useALL(Sales)to remove any existing filters on the table so we can scan the whole thing. - CALCULATE(SUM(Sales[SalesAmount]), ...):
CALCULATEthen sums theSalesAmountbut only for the filtered context we just supplied (the one-row table from the previous day).
When to Use This Method
Use it when you need a fixed value added to your table. However, calculated columns use memory and increase the size of your model. For dynamic calculations in your reports, a measure is almost always a better choice.
Method 2: The Best Practice - Measures for Time Intelligence
For most reporting, you don't need a static column. You need a dynamic measure that responds to the filters in your visuals (like a date slicer). This is where Time Intelligence functions shine.
Important Prerequisite: These functions require a properly configured Date Table. This is a best practice in Power BI. Your model should have a separate table with a continuous list of dates, and this table should be marked as the official date table and have a relationship to the date column in your fact table (like your Sales table).
Step 1: Create a Basic Sales Measure
First, make sure you have a base measure for your core value. This makes your other DAX formulas cleaner and more reusable.
Total Sales = SUM(Sales[SalesAmount])Step 2: Create a Measure for Previous Period Sales
Now, right-click on your table in the Fields pane and select "New measure". Here’s how you’d calculate the previous month's sales.
Previous Month Sales (Measure) =
CALCULATE(
[Total Sales],
DATEADD('Date'[Date], -1, MONTH)
)Step 3: Understanding this Simpler Formula
This is much easier, isn't it?
- [Total Sales]: The base measure we want to calculate.
- DATEADD('Date'[Date], -1, MONTH): This is the magic. It takes the dates in the current filter context (e.g., in a table visual, it’s the current month on that row) and shifts them back by the interval you specify. Here, we're shifting back by -1 MONTH.
- CALCULATE(...): It simply evaluates
[Total Sales]using that new, time-shifted filter context.
You can easily adapt this for other intervals:
- Previous Day:
DATEADD('Date'[Date], -1, DAY) - Previous Quarter:
DATEADD('Date'[Date], -1, QUARTER) - Previous Year:
DATEADD('Date'[Date], -1, YEAR)orSAMEPERIODLASTYEAR('Date'[Date])
Method 3: When It's Not a Date - Using OFFSET
What if your "rows" aren't defined by time? Maybe you've sorted products by price and want to compare each product to the one priced just below it. This is where the modern window functions, especially OFFSET, are perfect.
Imagine a table of Products sorted alphabetically. We want to get the stock count of the previous product in that alphabetical list.
Step 1: Create the Measure
Create a new measure in your Products table.
Previous Product Stock =
CALCULATE(
SUM(Products[StockCount]),
OFFSET(
-1,
ALLSELECTED(Products[ProductName]),
ORDERBY(Products[ProductName], ASC)
)
)Free PDF · the crash course
AI Agents for Marketing Crash Course
Learn how to deploy AI marketing agents across your go-to-market — the best tools, prompts, and workflows to turn your data into autonomous execution without writing code.
Step 2: Breaking Down the OFFSET Logic
OFFSET is incredibly powerful. Here's what its arguments are doing:
- -1: This tells Power BI to move back one position. A
1would move forward, and0would return the current row. - ALLSELECTED(Products[ProductName]): This defines the "window" or partition of data we are working within. It's the full table of products that are currently visible after any slicers have been applied.
- ORDERBY(Products[ProductName], ASC): This is the most important part. It tells
OFFSEThow the data is ordered. This criteria defines what "previous" actually means. Here, we’re ordering by the product name in ascending (A-Z) order.
When you put this measure in a table visual with ProductName and StockCount, it will calculate the stock for the product on the row directly above it, based on the alphabetical sort order.
Final Thoughts
Navigating row-level calculations in Power BI is a common hurdle, but it's manageable once you shift your thinking from a static spreadsheet grid to a dynamic data model. For date-based comparisons, using a Date table and DAX Time Intelligence functions is the cleanest and most efficient path. For non-date scenarios where physical order matters, the modern OFFSET function gives you precise control over finding that "previous row" value.
As you can see, performing these kinds of analyses often means figuring out the right DAX function and carefully crafting formulas, which is a big learning curve. We built Graphed because we believe getting insights shouldn't require you to become a DAX programmer. By connecting your data sources, you can just ask questions in plain English, like "compare this month's revenue to last month by product category," and get a real-time dashboard instantly. It automates away the code-writing and configuration so you can focus on the insights in your data, not the syntax.
Related Articles
How to Create Facebook Ads API for Claude Code
Create a Meta Marketing API access token that never expires, using a system user, so Claude Code can pull Facebook ad reports and manage campaigns.
ClickHouse vs Postgres: When to Switch to Columnar
Comparing ClickHouse vs PostgreSQL means matching storage architecture to workload. Row storage wins for transactions. Columnar wins for scan-heavy analytics.
Google Ads for Orthodontists: Get More Booked Consults
Most orthodontic Google Ads campaigns waste money on low-intent searches. The problem is structure, not the platform.