# Working with Averages in DAX using AVERAGEX, SUMMARIZE and DATESINPERIOD

In this blog post, we are going to dive into the world of averages and how to solve problems when calculating averages by using CALCULATE, SUMMARIZE and AVERAGEX. Specifically, we look at creating an average calculation across months and as you will see in the video below, this can be a challenge on multiple levels!

## Working with SUMMARIZE and SUMMARIZECOLUMNS in DAX

Our goal in this video is to return the average sales for the last 3 months, see Figure-1 below. Figure 1 – Average of last 3 months of sales

Our first attempt at solving this problem may be to just use the expression AVERAGE([Sales Amount]) as seen in Figure-2 below. However, the AVERAGE function will first return the AVERAGE of all the transactions for the month and therefore the results of the following calculation are not quite as expected: Figure 2 – Average of Sales Amount, incorrect calculation.

The result of the expression in Figure 2 can be seen in the following screenshot. Ultimately, average is returning the SUM of the Sales Amount divided by the number of transactions for each month. Figure 3– Average of Sales Amount

Now that we understand this behavior and what is occurring, we can take a direct approach at solving the problem. First, we need to create a virtual table that contains the months along with their total sales. In order to create this aggregated table we can use SUMMARIZE or SUMMARIZECOLUMNS. In this scenario I will use SUMMARIZE because SUMMARIZECOLUMNS doesn’t quite work correctly within a modified filter context and we will need to change the default filter context to get 3 months in our aggregate table.

The following expression will return an aggregate table with the Year, Month and Total Sales. Figure 4 – Creating a virtual, aggregated table with SUMMARIZE

SUMMARIZE is a function that will return a table expression and therefore you would get an error message if you tried to just put this expression in a calculated measure. However, you could test this out or “DEBUG” this expression by putting it in a calculated table or running the expression from Dax Studio. See the results of this expression from Dax Studio below in Figure 5: Figure 5 – A view of the virtualized table created by SUMMARIZE

## Working with AVERAGEX, CALCULATE and DATESINPERIOD

There are a few challenges still left to solve to get our desired result. First, you can’t use the AVERAGE function on a table or table expression, you must provide a column and therefore the result produced by SUMMARIZE here cannot be used by AVERAGE. However, X Functions like AVERAGEX accept a table or table expression as their first parameter and therefore work perfectly with this virtual table.

The next challenge is that the virtual table is returned within the current filter context and therefore we would always be returning the AVERAGE of the current month and only the current month. UNLESS, we use the CALCULATE function to evaluate the expression within a modified filter context, which is exactly what we would do! The calculation in Figure 6 below is the expression that returns the desired result seen in Figure 1. Figure 6 – Final calculation

# ALL vs ALLSELECTED in DAX and Power BI Desktop

Hey all! In my latest YouTube video  on DAX I discuss how ALLSELECTED can be leveraged in Data Analysis Expressions (DAX). This continues a series of YouTube videos in which I discuss various DAX functions and how to use them in Power BI Desktop.

Please feel free to check out my YouTube channel and subscribe at https://www.YouTube.com/c/MitchellPearson

If you want to watch the video of this function explained, please take a look below:

## ALLSELECTED function in DAX and Power BI Desktop

First, let’s look at the definition of ALLSELECTED, provided inside Power BI desktop when referencing the function: ALLSELECTED: Returns all the rows in a table, or all the values in a column, ignoring any filters that may have been applied inside the query, but keeping filters that come from the outside.

What does this mean? Well, it means that it will essentially ignore filters coming from that visual but still respect filters coming from slicers and filters outside that visual (the outer query)! And yes, this is pretty awesome as you will soon see.

## ALL vs. ALLSELECTED DAX functions

The biggest difference between ALL and ALLSELECTED is that the ALL function ignores all filters, regardless of where they are coming from. In contrast, the ALLSELECTED function only ignores filters that are coming from the inner query.

## Returning Total Sales of all Selected Countries

The following expression in DAX would return the total sales for all countries in all scenarios. For example, the countries Australia, Canada and France were selected in the slicer, but yet the measure Total Sales All Countries still returns the total sales across all countries: Figure 1.1

In this scenario, you might want to return Total Sales for all countries selected in the slicer (allselected), \$13,682,863.16. This can be quite tricky, especially if you didn’t know of the existence of the ALLSELECTED function. Let’s write the expression in Figure 1.1 a different way and look at the results. Figure 1.2

In this example you can clearly observe that ALLSELECTED is providing different way to analyze your data. I love this dynamic approach to analyzing data that is provided by simply modifying the ALL function to use ALLSELECTED!

As always, I hope this blog has helped someone somewhere and thanks for reading my blog!!

# HASONEVALUE vs ISFILTERED in DAX

I use the function HASONEVALUE quite often, many times it is in the context of solving problems with the total row. I wrote a blog on how to handle totals using HASONEVALUE here:

Unfortunately, HASONEVALUE is not always the tool for the job. For this scenario I am returning Homes Sold Month-to-Date. The final solution should look like the following screenshot: As you can see in the previous image we want to return the Homes Sold MTD if we are at the day level or the month level, but if we are at a level higher than the month level then we simply want to return a blank value. It doesn’t make sense in this scenario to show MTD homes sold at the quarter or year level. If we use HASONEVALUE(‘date’[Date]) here, then no value is returned at the Month level. Here is an example: As you can see in this example, a blank value is returned for the month of January. As previously mentioned the desired behavior is to return a value for the month of January.

## IsFiltered

IsFiltered: Returns TRUE when columnName is being filtered directly. Else, False.

Let’s take a look at what IsFiltered returns if we are checking to see if the date is filtered: ISFILTERED returns False for the month and Year as expected. Now, we can simply chain multiple IsFiltered functions together to return our desired results. In the following screenshot I added an or condition to check if the month was also filtered. As you can see, the results now return TRUE at the day and month level. Now we can apply some conditional logic using the IF function based on the results of the IsFiltered expression in example above. If the day or month IsFiltered then return the MTD homes sold, else return BLANK(). See below: Thanks for checking out my blog!

# Semi additive measures in DAX and Closingbalancemonth

It’s been a while since we have visited Data Analysis Expressions (DAX) on this blog, but now we’re going to jump right in and discuss working with semi-additive measures. Semi-additive measures can’t be added across all dimensions, typically they can’t be added across the date/time dimension. Common examples of semi-additive measures are account balances and inventory levels.

• Inventory levels can be added up across products, across different stores, but not across time. If you have 500 silver widgets at the end of day on Monday and you have 500 silver widgets at the end of day on Tuesday, how many widgets do you have? You only have 500 of course! We have to take this into consideration when building our model and measures.
• The same is true of account balances as well. If I have \$100 in my account on February 1st and I have \$85 in my account on March 1st, what is my account balance? It’s only \$85, it’s not the sum of both months.

## The Scenario

In this scenario, I am looking at the stock price of Microsoft over time. We want to determine things like Closing and Opening price among others. For this example we are going to try and calculate the closing price for the month using the function CLOSINGBALANCEMONTH. This will present an interesting problem that we will discuss shortly. First, my data model has a simple measure which returns a SUM of the closing stock price as seen below: Remember, this measure is valid for all the dimensions in my data model except for my date dimension. Similar to inventory levels and account balances we don’t want to add the closing stock price across time, this produces incorrect results. Back in 2012 the stock price of MSFT stock was around \$30 a share, however, when I display our measure in a table with the year and month what we actually see are numbers that are much higher. This is because the measure is adding up the stock price for all days of the month and this is incorrect! ## CLOSINGBALANCEMONTH

Definition: Evaluates the expression of the last date of the month in the current context.

Syntax: CLOSINGBALANCEMONTH( <expression>, <dates>)

CLOSINGBALANCEMONTH is one of the built in time intelligence functions and it works great, most of the time. Where it falls short is when you have blanks or gaps in your data. I am going to create a new measure using CLOSINGBALANCEMONTH using the following expression: Now let’s take a look at the results: Most months we are getting the correct value, but some months are blank, why? CLOSINGBALANCEMONTH returns the closing price of the stock for the last day of the month, unfortunately we are looking at stock market data and the stock market is not open every day of the month. So therefore, if the last day of the month has no closing stock price, then blank is returned. See screenshot below. This is typically not what we want when looking at semi-additive measures! We want to return the closing balance for the last day of the month that had a value.

## LASTNONBLANK IN DAX to handle blanks!

We need to write a measure in DAX that is going to determine the last date of the month where the stock market was open. We are going to solve this problem by using the function LASTNONBLANK. This is an extremely useful and helpful function.

Definition: Returns the last value in the column, filtered by the current context, where the expression is not blank.

Syntax: LASTNONBLANK(<column>, <expression>)

I am going to build this out incrementally for demonstration and validation purposes. First, we are going to create a new measure just to see what this function returns: Next, I will add this new measure to our table for validation. Everything looks perfect! The measure is not blindly returning the last day of the month, it’s returning the last day of the month that had a closing price for the stock, meaning the value returned for June, September, and March is exactly what we need. ## The False Positive

With our knowledge of DAX we may now attempt modify our Close Price measure with the following: This now returns the following results: BOOM! Winner winner chicken dinner, I’m taking the rest of the day off and going to the beach! Wait a minute…. was the topic false positive?

Are the results above correct? Yes the are, just take my word for it or else this blog post is going to really, really long. However, it’s really easy to author formulas in DAX that work at one level but don’t work at other levels, and this is because of Filter context. As developers we have to always consider how the end users might slice the data. For example, if a user is looking at the data at the day level, will our measure still return he closing price for the month? Let’s check. Immediately, we see two different items that tell us the measure is definitely not returning the end of month close price.

1. First, the close price and the close price (eom) measure have identical values, this means our closing month measure is displaying the closing price for each individual day. That tricky filter context got us again!
2. Secondly and most obvious, the close price (eom) values should be identical for every day of the month, they are not. Clearly this measure is not working. Back to the drawing board.

Go back and look at the definition for LASTNONBLANK, it works within the current filter context so when we filter our report down the day level it can only return that day.

## PARALLELPERIOD IN DAX

Now it’s time to introduce you to one more function in DAX and that is the PARALLELPERIOD function.

Definition: Returns a table that contains a column of dates that represents a period parallel to the dates in the specified dates column, in the current context, with the dates shifted a number of intervals either forward in time or back in time.

(I just read that definition and now I’m confused….)

Syntax: PARALLELPERIOD(<dates>, <number_of_intervals>,<interval>)

The PARALLELPERIOD function will return all the dates in the interval that we specify within in the current context. What does that mean??? If you were looking at January 1st and you used PARALLELPERIOD to return all the dates at the month level then a table would be returned with all 31 days for January. This means that we can now return the closing price for the month even if the user is exploring the data at the day level!! I can feel your excitement as I write this.

Let’s jump right in and look at the final DAX expression. I am once again going to modify my existing calculated measure, this time I’m replacing ‘date’[date] with PARALLELPERIOD: Enjoy!

# Unexpected Totals in DAX (Part 3)

At some point or another every DAX author realizes that the total row is not the sum of each row/cell in a given column. This can be quite confusing and is exactly why I am writing a third blog post dedicated to the total row.  If you missed part one or part two in this series you can find them below:

## Problem

In this blog, we want to return YTD Sales for previous months and Forecast YTD Sales for the current month. Therefore, there should be only one measure and that measure should return YTD Sales or Forecast YTD based on the month.

In the following table there are three measures, the first measure is YTD Sales and it tracks the actual sales. The second measure is Forecast YTD Sales and this is the forecasted sales. The third measure is the Dynamic Measure, this is the proposed measure designed to replace the other two measures. However, the total row produces unexpected results, and therefore is perfect for this blog post: In the above screenshot, the total row for the dynamic measure is displaying \$19,582,120 but the sum of all the rows is actually \$28,164,680. Let’s take a look at the dynamic measure and figure out why the total row is not what we might expect.

## Dynamic Measure

The “Dynamic Measure” is returning the YTD Sales for completed months and returning the Forecast YTD Sales for the current month. Let’s take a quick look at the measure just to understand better what is going on. Please note, for this example we assume there are sales for every day of the year. • A = Two variables to make the code more readable (See descriptions below):
• LastSaleDate = Return the last day the company had a sale (in the current filter context)
• LastDayOfMonth = Return the last day from the date table (in the current filter context)
• B = The logical test performed by the IF function.
• If the two variables don’t match, then it is the current month and [Forecast YTD Sales] is returned.
• If the two variables do match, then it is a completed month and [YTD Sales] is returned.

## Filter Context of the Total Row

The total row is executing the dynamic measure within the context at the total row. What is the last day in the date table within the current filter context? At the total row it is 12/31/2008, there is a filter on the report page that filters the report down to only the year 2008. The last day that there was a valid sale was on 6/20/2008. Since 12/31/2008 does not equal 6/20/2008 the calculation returns Forecasted YTD Sales, which at the total level is \$19,582,120.60.

Steps to solve this problem:

1. Determine if the calculation is at the total row.
2. For the total row perform the Dynamic Measure calculation for each month in the table separately.
3. Sum the results of each result separately.

However, steps two and three above are a little bit more complex than they sound and therefore to complete the solution we need to introduce you to two new functions in the DAX language: VALUES and SUMX. The great news is this is a design pattern that you will be able to use in many different scenarios!

## The VALUES function in DAX

MSDN Definition:
Returns a one-column table that contains the distinct values from the specified table or column.

Remember step 2 from above? We want to execute our dynamic measure against each row in the table, the VALUES function will get us the distinct list of the months. Let’s take a look at the VALUES function in action. I have created a table using the following formula to display the results:  The VALUES function returned a distinct list of months. This is exactly what we need. Now, how do we execute our measure against each row in this table and then SUM all the results at the very end to get the expected value at the total row? SUMX!!

## Working with the SUMX Function in DAX

MSDN Definition: Returns the sum of an expression evaluated for each row in a table.

Syntax: Perfect! The SUMX function is going to iterate over the list of months and execute the dynamic measure against each month. After this process has completed the SUMX function will then SUM the results returned for each month.

SUMX accepts two parameters, the first parameter is a table and the second parameter is the expression. The table that is returned from the VALUES function is the first parameter and the dynamic measure is passed in as the second parameter (expression). Let’s take a look at the final solution.

## Solution

The following solution now returns the expected results for the total row: Here are the results, pay special attention to the total row: # Unexpected Totals in DAX (Part 1)

DAX is an awesome language and when paired with properly created relationships, DAX can add significant analytical value to your data models with minimum effort. But, you already knew that! So why are we here? Well, sometimes, DAX can produce results that are unexpected and this is usually very noticeable when looking at the totals row. So why do we get unexpected results at the total row? Why doesn’t the total row simply return the sum of all the rows in a specified column? The simple answer is your DAX calculation is also computed for the total row and operates within the contexts of the total row. Let’s take a look at the previous screenshot.

In this example, the total row is returning all homes listed for all years in the filter context, this is in fact the sum of all the rows in the column. However, you may expect to only see the homes newly listed on the market for the latest time period, in this case that would be how many homes were listed in 2016. The result of 8,691 homes listed in the total row is not wrong or incorrect, it depends on what you are specifically looking for, it could definitely be unexpected depending on your analytical needs. If you do not wish to see the total of all homes ever listed in the current filter context then you have a couple of options available to you.

There are generally 3 ways you could address incorrect / unexpected totals.

1. Pretend the problem doesn’t exist. (ProTip: Don’t ignore problems.)
2. Identify when the DAX calculation is being evaluated for the total row and return a BLANK value.
3. Identify when the DAX calculation is being evaluated for the total row and perform a different calculation.

In this blog post you are going to learn how to return blank to eliminate any confusion. In a future blog post you will learn how to use DAX to change the value of the total row.

## HASONEVALUE function in DAX

In this simple example, the total row is the sum of all the rows, but this is not what we want. What we would want to show at the total row is how many homes have recently been listed for sale, not the total of all homes that have ever been listed. The first thing we must do is identify if we are at a total row. The way I do this is by using the function HASONEVALUE.

MSDN Definition:

HASONEVALUE: Returns TRUE when the context for the columnName has been filtered down to one distinct value only. Otherwise FALSE.

In the screenshot below I created a new measure called “Totals” and in this measure the function HASONEVALUE is used to correctly identify which row is the total row. This works because at the total level the filter context is all years, so the function returns FALSE. The final step is to now use conditional logic and replace the Total row with a blank value.

## BLANK() function in DAX

New Homes on Market (2)=
IF(
HASONEVALUE(‘Date'[Year]),
[New Homes on Market],
BLANK()) Now the total row is no longer confusing or misleading. In part two of this series I am going to take this a step further and show how to use DAX to return your expected results at the total row instead of just returning blank!

Further Reading: Rob Collie over at PowerPivotPro has a great blog post on HASONEVALUE vs. ISFILTERED vs. HASONEFILTER:
https://powerpivotpro.com/2013/03/hasonevalue-vs-isfiltered-vs-hasonefilter/

Thanks!

# Power BI–Problem, Design, Solution (Text Search)

There is a video that walks you through the solution in depth, please find the video at the end of this post along with the completed solution.

In this installment of the Problem, Design, Solution series we are going to show you how to perform a text search using slicers in Power BI, this simulates a “LIKE” type search. In the following screenshot you can see that when “Tax” is selected all records in the table that have “Tax” anywhere in the record are returned, likewise whenever “IT” is selected from the slicer all records in the table that have IT in them are returned. Hope you enjoy this post! ### Problem

Normally slicers (visual filters) only filter records that are an exact match, for example, if you select “IT” from the slicer then you would only expect to see records that have IT and only IT in the record, if it does not match IT exactly then those records are not returned. This is the intended behavior of a slicer and in general, this is exactly what we want. However, there are times when you might want to do a “LIKE” type search similar to the like function in T-SQL. In this scenario, we had a client who needed to do this exact thing. The screenshot below is our simulated problem for this example.

In order to bring back all records that contain “IT” you are required to click each occurrence of “IT” in your slicer, of course, this isn’t a big problem if you have a small number of possible combinations like our sample size. In larger environments, this may be an unreasonable expectation! ### Design

Now that we have discussed both the problem and what we want the ultimate solution to look like, it is time to lay out the design. The design includes a four step process.

Let’s break this down a little bit:

• The first step in the process is to identify all the unique values that we need to filter on and put those values into their own distinct table, in this case, we are looking at departments (HR, IT, FIN, Audit, and Tax).
• The second step is to create a measure that uses the distinct departments in our new table as a filter. We will call this measure IsFiltered.
• The third step is to create a new slicer using the values listed in our disconnected table.
• The final step is to tie our new measure (IsFiltered) to the specific visual that we want to be affected by our disconnected table of distinct values.

I would recommend storing this list of values in a file or in a table in a database, for this example I will quickly put these values into a table in my PBIX file. Navigate to the home ribbon and select “Enter Data”, I will name the column Departments and the table Slicer, next I will add the five distinct departments as records for the departments’ column (IT, HR, Tax, FIN, Audit).

Note: This is using the disconnected table design, we are not going to set up a relationship between this new table and any other table in our model. #### Step 2 – Creating the IsFiltered measure

This IsFiltered measure is going to give us the “LIKE” type search that we are looking for! Excited yet?? Well, you should be! In this example I am going to use the FIND function, the find function is exactly like the SEARCH function with the key difference being that the FIND function is case-sensitive and the SEARCH function is case-insensitive. The code below will complete step 2 in our design.

IsFiltered =
IF(
SUMX(‘Slicer’,
FIND(
‘Slicer'[Departments],
MAX(‘Department Goals'[Affected Departments]),,0)) > 0,
True“,
False
)

What is this measure doing? The FIND function returns the starting position of the text string we pass in, if the value is greater than 0 then that means that the text exists and this is how we generate a LIKE type search. If the text is not found then nothing is returned and we give that record a default value of 0.

#### Step 3 – Create a slicer from the disconnected table

Now we can create a slicer from our distinct list of values. At this point the slicer does not filter anything, this is because the filtering occurs through the measure we created in step 2 and needs to be added as a filter to a visual or report in our Power BI Report. #### Step 4 – Use the IsFiltered measure to filter a visual in the report

The last step in this process is about as easy as step 3, first we need to figure out which visuals we want to be filtered with the “LIKE” type operation and then we need to use the IsFiltered measure as a filter on those visuals. The criteria here will be to only show the records where the result is “True”. Remember the DAX calculation from above? If a value was found, then a number higher than 0 is returned and we flag the record as “True”!

Finally, I am going to add the IsFiltered measure as a filter to my table visualization, this is done in the Fields section of the visualizations pane. See the below image: ### Solution

With the 4 step design completed, the solution is also complete! Now we can apply a filter that does a text search rather than an exact match, see the image below: ### Summary

By leveraging the DAX expression language we are able to override the default behavior of slicers and filters in Power BI. Please note that this solution would also work in an SSAS Tabular model, the implementation would be slightly altered as you may be consuming that model from excel rather than Power BI but it would work nonetheless!

### Resources

Video of the solution:

Completed Example:

http://tinyurl.com/yd2qon7x