You are on page 1of 557

Power BI DAX Simplified

DAX and calculation language of Power BI demystified by practical


examples

Author: Reza Rad


July 2021
Edition one
PUBLISHED BY
RADACAD Systems Limited
web address[https://radacad.com/]

24 Riverhaven Drive,
Wade Heads,
Whangaparaoa 0932
New Zealand
Copyright © 2021 by RADACAD, Reza Rad
All rights reserved. No part of the contents of this book may be reproduced
or transmitted in any form or by any means without the written permission
of the publisher.
Agenda
AGENDA

ABOUT THE AUTHOR

INTRODUCTION: FROM THE AUTHOR

PART 1: FUNDAMENTALS

CHAPTER 1: BASICS OF DAX EXPRESSION IN POWER BI


CHAPTER 2: M OR DAX? THAT IS THE QUESTION!
CHAPTER 3: SCENARIOS OF USING CALCULATED TABLES IN POWER BI
CHAPTER 4: MEASURE VS. CALCULATED COLUMN: THE MYSTERIOUS
QUESTION? NOT!
CHAPTER 5: POWER BI DAX BACK TO BASICS: SCALAR VS. TABULAR
FUNCTIONS
CHAPTER 6: DAX VARIABLES: BETTER READABILITY, CONSISTENCY, AND
PERFORMANCE IN POWER BI CALCULATIONS
CHAPTER 7: CAUTION WHEN USING VARIABLES IN DAX AND POWER BI

PART 2: AGGREGATION AND ITERATORS

CHAPTER 8: SUM VS. SUMX; WHAT IS THE DIFFERENCE BETWEEN THE TWO
DAX FUNCTIONS IN POWER BI?
CHAPTER 9: CALCULATE TOTALS IN POWER BI: USING ITERATORS IN DAX
CHAPTER 10: SHOWING RANKING IN A VISUAL IN POWER BI USING RANKX
DAX FUNCTION
CHAPTER 11: GENERATING ROW NUMBER IN POWER BI VISUALIZATION USING
DAX

PART 3: FILTER
CHAPTER 12: FILTER FUNCTION IN DAX AND POWER BI: APPLY CUSTOM
FILTER TO CALCULATIONS
CHAPTER 13: NOW YOU SEE ME! USE CASES OF THE ALL DAX FUNCTION IN
POWER BI
CHAPTER 14: HOW TO USE THE ALL IN A DAX EXPRESSION IN POWER BI
CHAPTER 15: REMOVING THE TOTAL VALUE FOR A COLUMN IN THE TABLE
VISUAL OF POWER BI USING ISFILTERED
CHAPTER 16: FIND THE DATA VALUE USING LOOKUPVALUE DAX FUNCTION
IN POWER BI; SIMPLE AND USEFUL
CHAPTER 17: THE IF AND FILTER ARE DIFFERENT! BE CAREFUL (DAX)
CHAPTER 18: OVERWRITE INTERACTION OF POWER BI WITH DAX

PART 4: RELATIONSHIP FUNCTIONS

CHAPTER 19: GET A FIELD VALUE FROM A RELATED TABLE IN POWER BI: DAX
RELATED FUNCTION EXPLAINED
CHAPTER 20: POWER BI DAX RELATEDTABLE FUNCTION: GET THE SUBTABLE
RELATED TO THE CURRENT ROW
CHAPTER 21: USERELATIONSHIP OR ROLE-PLAYING DIMENSION; DEALING
WITH INACTIVE RELATIONSHIPS IN POWER BI
CHAPTER 22: DAX CROSSFILTER FUNCTION IN POWER BI: WRITE THE
FORMULA BOTH-DIRECTIONAL, BUT KEEP THE RELATIONSHIP SINGLE-
DIRECTIONAL

PART 5: LOGICAL FUNCTIONS

CHAPTER 23: WRITE CONDITIONAL STATEMENT USING SWITCH IN DAX


AND POWER BI
CHAPTER 24: STOP DAX CUMULATIVE TOTAL CALCULATION IN POWER BI
CHAPTER 25: DAX AND CONDITIONAL FORMATTING BETTER TOGETHER: FIND
THE BIGGEST AND SMALLEST NUMBERS IN THE COLUMN

PART 6: TIME INTELLIGENCE

CHAPTER 26: POWER BI DATE DIMENSION; DEFAULT OR CUSTOM? IS IT


CONFUSING?
CHAPTER 27: CREATING CALENDAR TABLE IN POWER BI USING DAX
FUNCTIONS
CHAPTER 28: ALL IN ONE: SCRIPT TO CREATE CALENDAR TABLE OR DATE
DIMENSION USING DAX IN POWER BI
CHAPTER 29: DAY OF YEAR AND DAY OF QUARTER – DAX CALCULATIONS FOR
POWER BI
CHAPTER 30: GET THE DAY OF THE WEEK NAME AND NUMBER IN POWER BI
USING DAX
CHAPTER 31: SOME METHODS FOR CALCULATING QUARTER IN DAX FOR
POWER BI
CHAPTER 32: BASICS OF TIME INTELLIGENCE IN DAX FOR POWER BI; YEAR
TO DATE, QUARTER TO DATE, MONTH TO DATE
CHAPTER 33: MONTH OVER MONTH CALCULATION IN POWER BI USING DAX
CHAPTER 34: DATESINPERIOD VS. DATESBETWEEN; DAX TIME INTELLIGENCE
FOR POWER BI
CHAPTER 35: DATEADD VS PARALLELPERIOD VS SAMEPERIODLASTYEAR;
DAX TIME INTELLIGENCE QUESTION
CHAPTER 36: SAME PERIOD LAST YEAR TO DATE DAX CALCULATION IN
POWER BI
CHAPTER 37: WEEK TO DATE CALCULATION IN POWER BI WITH DAX
CHAPTER 38: CALCULATE DURATION IN DAYS HOURS MINUTES AND SECONDS
DYNAMICALLY IN POWER BI USING DAX
CHAPTER 39: PREVIOUS DYNAMIC PERIOD DAX CALCULATION

PART 7: TABLE MANIPULATION FUNCTIONS

CHAPTER 40: CREATING A TABLE IN POWER BI USING DAX TABLE


CONSTRUCTOR
CHAPTER 41: USING DATATABLE DAX FUNCTION FOR CREATING
STRUCTURED TABLE IN POWER BI
CHAPTER 42: SOME SIMPLE WAYS TO DEBUG YOUR DAX MEASURE CODE IN
POWER BI: DEBUGGING VIRTUAL TABLES
CHAPTER 43: HOW TO USE ADDCOLUMNS FUNCTION IN DAX AND POWER BI
CHAPTER 44: CREATE A SUBSET OF THE TABLE IN POWER BI AND ADD
CALCULATIONS USING SELECTCOLUMNS DAX FUNCTION
CHAPTER 45: TOPN DAX FUNCTION: HOW IT WORKS IN POWER BI?
COMPARISON AGAINST THE TOP GROUP
CHAPTER 46: BUILDING A VIRTUAL RELATIONSHIP IN POWER BI – BASICS OF
TREATAS DAX FUNCTION
CHAPTER 47: CREATING RELATIONSHIP BASED ON MULTIPLE FIELDS IN
POWER BI USING TREATAS DAX FUNCTION
CHAPTER 48: AGE BANDING IN POWER BI USING TREATAS DAX FUNCTION
– RELATIONSHIP BASED ON BETWEEN
CHAPTER 49: AGGREGATED TABLE IN POWER BI WITH EXTRA OPTIONS –
SUMMARIZE FUNCTION IN DAX
CHAPTER 50: AGGREGATED TABLE IN POWER BI – USING GROUPBY
FUNCTION IN DAX
CHAPTER 51: COMBINING TABLES IN POWER BI: UNION, EXCEPT, AND
INTERSECT IN DAX
CHAPTER 52: CREATING A LIST OF NUMBERS OR DATES IN POWER BI USING
GENERATESERIES FUNCTION IN DAX
CHAPTER 53: CREATE A TABLE WITH A TO Z CHARACTER VALUES IN POWER
BI USING DAX

PART 8: TEXT FUNCTIONS

CHAPTER 54: SUBSTRING IN DAX: HOW TO GET PART OF STRING FIELD IN


POWER BI USING DAX EXPRESSION
CHAPTER 55: FIND A TEXT TERM IN A FIELD IN POWER BI USING DAX
FUNCTIONS
CHAPTER 56: SEARCH IN POWER BI TABLE VISUAL USING A SLICER FOR
CONTAINS CHARACTER CRITERIA
CHAPTER 57: SEARCH FOR ALL THE TEXTS IN POWER BI TABLE VISUAL WITH
THE FIRST THREE CHARACTERS SELECTED IN THE SLICER

PART 9: PARAMETER TABLE

CHAPTER 58: POWER BI WHAT IF PARAMETER FOR GETTING THE SALES OF X


MONTHS AGO: USE CASE SCENARIO
CHAPTER 59: DYNAMICALLY CHANGE THE FORMAT OF VALUES IN POWER BI

PART 10: PARENT-CHILD FUNCTIONS


BOOK WRAP UP

OTHER BOOKS FROM REZA RAD


About the Author

Reza Rad is a Microsoft


Regional Director[https://rd.microsoft.com/en-us/reza-rad], an Author,
Trainer, Speaker, and Consultant. He has a BSc in Computer engineering;
he has more than 20 years of experience in data analysis, BI, databases,
programming, and development, mainly on Microsoft technologies. He is
a Microsoft Data Platform MVP[https://mvp.microsoft.com/en-
us/PublicProfile/4030647?fullName=Reza%20%20Rad] for 11 straight
years (from 2011 till now) for his dedication to Microsoft BI. Reza is an
active blogger and co-founder of RADACAD[https://radacad.com/]. Reza is
also co-founder and co-organizer of the
Difinity[http://difinity.co.nz/] conference in New Zealand, and the Power BI
Summit[https://www.globalpowerbisummit.com/] (the biggest Power BI
conference)
CEO at RADACAD
Chairman and Director at Power BI Summit
Chairman and Director at Difinity conference (Since 2017)
Microsoft Regional Director (Since 2018)
Microsoft Data Platform MVP (Since 2011)
Leader of Data, Insights, and Power BI user group in Auckland, New
Zealand (Since Microsoft Fast Track Recognized Solution Architect
– Power Platform
Power BI All-Star award winner
Microsoft Power Platform Fast Track Solution Architect – Power BI
Dynamic Communities Emerald award winner
Author of more than ten books on BI, analytics, and Power BI
Speaker at many conferences such as Ignite, Microsoft Business
Applications Summit, PASS, etc.
Blogger and content creator
Consultant and trainer
Microsoft Certified trainer
Microsoft Certified professional
His articles on different aspects of technologies, mainly on BI, can be found
on his blog: https://radacad.com/blog[https://radacad.com/blog].
He wrote some books on Microsoft BI and also is writing some others. He
was also an active member on online technical forums such as MSDN and
Experts-Exchange, and was a moderator of MSDN SQL Server forums, and
is an MCP, MCSE, and MCITP of BI. He is the leader of the New Zealand
Business Intelligence users group[https://www.meetup.com/New-Zealand-
Business-Intelligence-User-Group/]. He is also the author of the very
popular book Power BI from Rookie to Rock
Star[https://radacad.com/online-book-power-bi-from-rookie-to-rockstar],
which is free with more than 1700 pages of content and the Power BI Pro
Architecture[https://www.apress.com/gp/book/9781484240144]. He also
wrote a book on Row-Level Security in Power
BI[https://www.amazon.com/gp/product/B082SFR2J4] and Basics of
Power BI modeling[https://www.amazon.com/gp/product/B08HWNZ7GC],
which are valuable assets for Power BI users.
He is an International Speaker in Microsoft Ignite, Microsoft Business
Applications Summit, Data Insight Summit, PASS Summit, SQL Saturday,
and user groups. And He is a Microsoft Certified Trainer.
*************************************
Connect to Reza
LinkedIn: Reza Rad[https://www.linkedin.com/in/rezarad/]
LinkedIn: RADACAD[https://www.linkedin.com/company/radacad]
Twitter: Reza Rad[https://twitter.com/Rad_Reza]
Twitter: RADACAD[https://twitter.com/RADACAD_COM]
Introduction: from the author
DAX is the language of data analysis in Microsoft Power BI, Azure
Analysis Services, and Excel Power Pivot. DAX is a powerful language that
can quickly empower you to analyze year-over-year or rolling 12 months
calculations. It is rare to find an analytics solution using Microsoft
technologies (especially Power BI) that doesn’t require some calculations to
be written by DAX.
As a Power BI (or Microsoft BI) developer, it is essential to learn this
language and master it. Learning a language is not just learning the
structure and functions. It is learning how, where, and when to use it so that
you can solve real-world problems with it.
In my training and consulting experience on Power BI, I realized that DAX
is the weak point for many Power BI users. DAX itself is not a complex
language. It is merely a language of expression. The complexity of learning
DAX is not the formula or the functions. It is how to use it in real-world
scenarios and how it performs on a dataset or visual.
I have been writing many blogs about DAX for many years. My blog
articles are all coming from my experience working with Power BI. I found
it helpful to compile them all in a book. Because my blog articles
practically explain things, I thought it better to title it as a practical way of
learning DAX by examples.
Indeed, there are books, articles, and Microsoft documentation on how each
function works where and how. However, learning these through an
example would bring a new way of understanding it.
A good analytics solution is a combined outcome of a good data model,
good data preparation, and good analytics and calculations. I have written
another book about the Basics of modeling in Power BI. This book is
covering the calculation and DAX aspects of it.
This book is for you if you are building a Power BI solution. Even if you
are just visualizing the data, calculations are an essential part of analytics.
You do need to have the calculation ready before visualizing it.
This is not a book to explain every single function in DAX. The approach in
this book is to have practical examples. Every chapter is based on real-
world examples of using a combination of functions to solve a challenge.
You can start from any chapter and finish at any chapter. The order of
chapters suggested in this book is just a guideline to help you have a
smooth flow of topics. Each chapter can be read without needing other
chapters. Examples of this book are designed in a way that you can use the
learning straight away in your Power BI file.
Although, this book is written for Power BI and all the examples are
presented using the Power BI. However, the examples can be easily applied
to Excel Power Pivot, Azure Analysis Services, or SQL Server Analysis
Service Tabular mode.
Most of the chapters of this book come from my blog articles and videos,
and countless comments from my readers are applied to it. If you ever feel
that you have a question that you can’t get through this book, feel free to
contact me directly.

Download the files and codes for this book from here
[https://radacad.com/books/files/PowerBIDaxRockStar.zip]
Part 1: Fundamentals
Chapter 1: Basics of DAX
Expression in Power BI

There are a lot of resources about how to use each function. However, you
always need to start with learning how the expression language works itself.
You need to know how to reference columns and tables. What operators can
be used, and what are the elementary basics of writing a DAX expression. In
this chapter, you will learn about that.

What is DAX?
DAX is an acronym for Data Analysis Expression language. This language
is used in Microsoft’s data analysis products: Power BI, Excel Power Pivot,
SQL Server Analysis Services Tabular Edition, and Azure Analysis
Services. The language is a combined version of a bit of T-SQL, Excel
formula, and C#.
DAX is an expression language, which means most of it is written after an
equal sign (=) as a formula. There are hundreds of functions that can be used
for doing different things. However, the expression language itself has some
fundamentals.

DAX as a calculation
DAX is most commonly written as a calculation. The calculation comes in
three forms below;
Calculated Column
Calculated Table
Measure

DAX as a calculation
This chapter will be very long if we want to discuss the difference between
these three types of calculations. You will learn about the different types of
calculations in the later chapters of this part.

DAX as a row-level security expression


DAX can also be used in writing logical expressions for row-level security
purposes. This means writing a calculation that only returns a Boolean value
(true or false).

DAX as a row-level security expression


To learn more about row-level security, I recommend you check out my
Row-Level Security book in Power BI.

DAX as a query language


DAX can also be used as a stand-alone query. However, you need to have a
specific setup to run that. You need to be connected the model using a tool
such as SSMS (SQL Server Management Studio) or DAX Studio. And then
write the query and get the results through those tools. Often, when we use
Power BI and Excel tools, the tool itself creates the query behind the scene.
Writing DAX as a stand-alone query is not happening very often. As a DAX
developer, you will spend most of your time writing DAX calculations, so I
focus on that part in this chapter.

DAX expression syntax


When you write DAX as an expression for a calculation. The expression
always comes after an equal sign (=). Here are a few examples:
=10
=”sample text”
=2*10
=Sum(TableX[ColumnY])
=Calculate( Sum(TableX[ColumnY]), TableX[ColumnZ]
=”sample text” )

all the examples above show an expression after the equal sign. The
expression can be a literal value such as a number or a text. If it is text, then
it is wrapped inside double quotes (“). You can use operators such as * or / in
the expression too. And You can use Functions (Such as Sum and Calculate
in the above samples), and you can refer to other columns, tables, and
measures.

Referencing objects
An essential part of a DAX expression is when you reference other objects.
For example, you can create a column, which can be precisely equal to
another column;
referencing a column in a DAX expression
To reference a column, you need the column name inside [ and ]. The table
name can appear before that. If you are using that column inside the same
table, you can skip the table name and just have it as below too;
Column = [FullName]

The above works as long as the Column I have created exists in the same
table that the FullName column exists. So as a best practice, it is advised to
have the table name before the column name. The table name comes just as-
is before the column name like below;
Column = DimCustomer[FullName]

If the table name has some special characters (and space is also considered
as a special character), then the table names come inside single quotes (‘)
like below;
referencing table names with special characters in DAX

This is how the expression will be;


Column = 'Dim Employee'[FirstName]

Calculated columns can be referenced similarly to regular columns.


Calculated tables can be referenced similarly to regular tables.
Measures can be referenced similarly as columns with [ and ] and the table
names in front of them. However, it is advised NOT to use the table name
for the measures because you may move your measures between
tables[https://radacad.com/move-measures-to-another-table-in-power-bi].

Operators
There are many operators you can use within DAX expressions. Operators
are in the below categories;
Operator samples operation
category Here
Arithmetic + adds two numbers
are
* multiplies two numbers
some
/ divides
sampl
Comparison = equal
es of
<> not equal
DAX
=> greater than or equal
expre
Text concatenation & concatenate texts
ssions
Logical && AND with
|| OR opera
IN if the value is IN the list
tors;
=1+10
=[ColumnX]+[ColumnY]
=”Reza”&” “&”Rad
=If( TableX[ColumnY]>=12, “XYZ”, “WYQ”)
=”Reza” IN {“Reza”,”Leila”}
= TableX[ColumnY]>=10 && TableX[ColumnZ]<20
Variables
You can define a variable inside a DAX expression. The variable can store a
single value or a table and can be re-used throughout that DAX expression.
When using variables in places that output is needed, a return keyword is
also mandatory. Here is an example of using variables;
Column 2 =
var HireYears=DATEDIFF('Dim Employee'[HireDate],TODAY(),YEAR)

return
if(HireYears>20,"hired for 20+ years","hired for less than 20 years")

As you can see, the variable HireYears is defined once and re-used in the IF
statement.

Comments
In every language, it is helpful to be able to write some none-executables
lines within the code. This will enable the developer to put some comments
for future reference. In DAX, you can write commentary using double
forward slash characters in one line (//)
writing a single-line comment in DAX

Or you can use /* and */ to write a comment in multiple lines;

Writing a multi-line comment in DAX


Comments are not executable and will not impact the performance or result
of the DAX expression.

Functions
And finally, the heart of DAX expression is filled with the usage of
functions. In DAX, there are functions for many different operations. A
function can be as simple as concatenating two text values. There are
functions to deal with date-based calculations, such as calculating the same
period last year. Each function gets input parameters and has an output.
Functions can be used inside each other. Here are some expressions with
functions;
Sum(TableX[ColumnY])
SumX ( All (TableX), [ColumnY]+[ColumnX] )
Functions have a wide variety, and usually, the intellisense (The pop-up
expression help screen when writing DAX) has good information about what
parameters the function needs and the generated output.

Using functions inside a DAX expression

Functions can be different, but one primary way to separated them is tabular
Vs. Scalar functions (although there are functions that are neither tabular nor
scalar). You will learn more about it in another chapter in this part.
Functions are also categorized based on the work they do. here are some of
the categories;
Date and time functions
Filter functions
Information functions
Parent and child functions
Time intelligence functions
table manipulation functions
logical functions
text functions
relationship functions

It is prevalent to use functions when you write DAX expressions. The


functions are giving your DAX calculation immense power, and being a
DAX developer; you need to learn how to work with the functions.

Change the font size of the DAX editor in


Power BI Desktop
You can use CTRL +/- to change the font size in the DAX editor in the
Power BI Desktop.

Color Guide on Power BI DAX Editor


When you write your DAX expression inside Power BI Desktop, you can
see a color code for some words. Here are what they mean;
Light green: Variables
Green: Comment
Purple: Measures
Blue: Functions (such as SUM, SUMX, Calculate), and
keywords (such as Year, return, var)
Red: Text values
Black: table and column names, literals, and operators
the screenshot below is an example with the colors mentioned.

DAX editor color codes in the Power BI Desktop

Summary
DAX as an expression language is used to create calculations in Power BI,
Excel Power Pivot, and Analysis Services. There are basics on how to
reference columns and tables. Some operators can be used in this expression
language. You can define variables for re-using part of the expression, and
you can write comments in the code. However, the heart of the DAX
expression is when you use functions, and that is where most of your time
will be spent when learning DAX.
Chapter 2: M or DAX? That is the
Question!

“What is the main difference between M and DAX? Why can we do a


calculated column in two different places? What are the pros and cons of
each? Which one should I use for creating a profit column? Why two
different languages?! Why structure of these two are so different?” If any of
these are your questions, then you need to read this chapter. In this chapter,
I’ll go through the differences between these two languages. I will explain
why, when, where of it.

What is M?
M is the scripting language behind the scene for Power Query. M is the
informal name of this language. The formal name is Power Query Formula
Language! This is a long name, and even Microsoft refers to it as M. M
stands for many things, but one of its most common words is Mashup. This
means this language is capable of data mashup and transformation. M is a
functional language. The structure of the M script can be similar to this:
M is a step-by-step language structure. Usually (Not always), every line in
the M script is a data transformation step. And the step after that will use
the result of the previous step. It is usually easy to follow the structure of
the M language for a programmer. Because it is understandable with
programming blocks of Let and In and some other programming language
features alike.

What is DAX?
DAX is Data Analysis eXpression Language. This is the common language
between SQL Server Analysis Services Tabular, Power BI, and Power Pivot
in Excel. DAX is an expression language, and unlike M, it is very similar to
Excel functions. DAX has many functions in common with Excel.
However, DAX is much more potent than the Excel formula in many ways.
Here is an example DAX expression:

DAX calculations are built in a way that makes sense mainly for Excel
users. Usually, Excel users are very comfortable with this language.
Everything goes through functions. DAX doesn’t have programming blocks
in it and combines function uses, filters, and expressions.

Example Usage of M
M can be used in many data transformation scenarios. For example, it can
be used to Pivot or Unpivot Data, To Group[https://radacad.com/grouping-
in-power-query-getting-the-last-item-in-each-group] it based on some
columns. Here is how a Pivot/Unpivot[https://radacad.com/pivot-and-
unpivot-with-power-bi] can work in Power Query;

Example Usage of DAX?


DAX can be used for many calculations for analyzing data. For example,
calculating Year To Date, Calculating Rolling 12 Months
Average[https://radacad.com/secret-of-time-intelligence-functions-in-
power-bi], or anything like that. Here is an example which based on
selection criteria in the report and few simple DAX expressions, we can do
a customer retention[https://radacad.com/lost-customers-dax-calculation-
for-power-bi] case with DAX;
Calculated Column Dilemma
The main question of choosing between DAX and M comes from the
calculated column dilemma, in my opinion. You can create many calculated
columns in both M or DAX, and it is confusing where is the best place to do
it or why there are two different places to do it?! For example, you can
create a full name concatenated of the FirstName and LastName columns.
You can do that in M and also in DAX. So this question comes up that:
Why two different places? Which one is best to use? can we always use one
language?
To answer this question, I would like to use another example; There are
many types of knives, and you can use almost all of them to cut cheese!
reference: here[http://forkitchen.blogspot.co.nz/2008/10/what-are-different-types-of-kitchen.html]
Almost every knife in the above picture can be used for cutting cheese
except one of them! So why are there so many knives for cutting cheese?!
The answer is that; these are not knives for cutting the cheese! Each knife is
good for doing one particular case. For cutting bread, a bread knife gives
you the best result. For cutting a fillet, you usually need another type of
knife. But as you agree, you can use many of these knives for some cases
(such as cutting the cheese!). Let’s now go back to the original question;
Why can I create the same calculated column in
DAX or M?
These two languages are built independently. They are made in a way that
they can handle most business-related solutions. So, as a result, there are
some use cases that both languages are capable of doing it. For example,
both of these languages can easily create a concatenated column of two
other columns.
Which one is best?
The quick answer is It depends! It depends on the type of usage. If you
want to create a concatenated column, Power Query (M) is a better option
in my view because that usually is like the ETL part of your BI solution.
You can build your model and data sets in the way you like them to be. But
if you want to create something like Year To Date, you can do that in Power
Query or M, but it will be lots of code, and you have to consider many
combinations of possibilities to create a correct result.
In contrast, in DAX, you can create that with the usage of the TotalYTD
function. So the answer is; there is no best language between these two. The
type of usage identifies which one is best. Usually, any changes for data
preparation are best to be done in M. Any analysis calculation on top of the
model is best to be done in DAX.
Two Languages for Two different Purposes
There are many programming languages in the world. Each language has its
pros and cons. JavaScript is a language of web scripting, which is very
different from ASP.NET or PHP. The same thing happens here. When M
was born, it meant to be a language for data transformation, and it is still
that language. DAX was created to answer business analysis questions.

What Questions Can DAX Answer?


DAX is the analytical engine in Power BI. It is the best language to answer
analytical questions which their responses will be different based on the
selection criteria in the report. For example; You might want to calculate the
Rolling 12 Months Average of Sales. It is tough to calculate that in M
because you have to consider all different types of possibilities; Rolling 12
months for each product, every customer, for every combination, etc.
However, if you use a DAX calculation for it, the analytical engine of DAX
takes care of all different combinations selected through Filter Context in
the report.

What Questions Can M Answer?


M is the language of data transformation in Power BI. You can use M for
doing any data preparation and data transformation before loading that into
your model. Instead of bringing three tables of DimProduct,
DimProductSubcategory, and DimProductCategory, you can merge them all
in Power Query and create a single DimProduct including all columns from
these tables, and load that into the model. If you decide to Load all of these
into the model and use DAX to relate these, it leads to consuming extra
memory for something that is not required to be in the model. M can
combine those three tables, and based on the “Step Based” operational
structure of M, they can be used to create a final data set.

As a Power BI Developer, Which


Language Is Important to Learn?
Both! With no hesitation! M is your ETL language, and DAX is the
analytical language. You cannot live with only one. If you want to be an
expert in Power BI, you should be an expert in both of these languages. You
will need a good understanding of both languages to understand which one
is best for which purpose and easily use it in real-world scenarios.
Chapter 3: Scenarios of Using
Calculated Tables in Power BI

Calculated tables first introduced in September 2015 update of Power BI


Desktop[https://powerbi.microsoft.com/en-us/blog/44-new-features-in-the-
power-bi-desktop-september-update/]. The name speaks for itself; these are
tables created by calculation. As these are in-memory tables, their
calculation is based on DAX (Data Analysis eXpression language). There
are many benefits of using Calculated tables, such as using them for role-
playing dimensions (for example, having more than one date dimension in a
model). There are some DAX functions and expressions that return a table
as a result, and using them as a table in your model sometimes is helpful.
For example, you might want to create a table for the top 10 customers and
then use that as the primary source table in many reports. In this chapter, I’ll
explain to you some use cases of calculated tables.

Role-Playing Dimension
The first functionality that appears in mind when we talk about Calculated
Tables is creating role-playing dimensions. Role-playing dimensions are
dimensions with the same structure and data rows that play different roles in
our data model. For example, the Date Dimension is a generic dimension.
However, you might have more than one date column in a sales transaction
table to relate with the date dimension. In the example below, we have three
date fields in the FactInternetSales table: Order Date, Ship Date, and Due
Date.

These three fields should be related to three different date dimensions. So


what you can do is to load the date dimension once in the Get Data section
from the data source. Here is the example date dimension loaded in Power
BI Desktop (through getting Data):
Now you can create role-playing dimensions by creating a Calculated table:

The calculated table will be created in memory and allows you to write the
definition of the table
The language for the table definition is DAX. For now, let’s keep it simple
to see how it works in action. We want an exact copy of the DimDate table
here. So you can use the ALL function in DAX as below:
Ship Date = ALL(DimDate)

As soon as you type the expression above and press Enter, You’ll see the
result underneath it as data rows and a list of columns in the Fields pane.
You’ve created a role dimension as simple as that. Now you can set up the
relationship;
I’ve also created a Due Date dimension for the relationship above and
renamed the original DimDate to Order Date.

In-Memory Structure, Less Refresh Time


Calculated table loads into memory, so your Power BI file size will
increase. However, you don’t need to reread them from the external data
source. You can create multiple views in the source database and connect to
them through the Get Data section with Power Query. However, their data
need to populate from the source database every time a refresh happens
(either scheduled or manual).
WITHOUT Calculated Tables: Here is an example of three date tables
loaded from the external data source:
WITH Calculated Tables: and here is only one date dimension loaded (for
the role-playing dimension example above):

As you can see, this is much more efficient in terms of reducing the refresh
time. However, the memory consumption would be the same in both
methods.
The date dimension was a small table. You might need role-playing for big
data tables. Calculated tables will save you a lot of time in refreshing data
in such cases.

DAX Table Functions


Some DAX functions return a table. For example, the ALL function, which
I used in the role-playing sample above. The ALL was a simple example of
a DAX function that returns the complete copy of the source table. Let’s
have a look at some other examples and see how it works in different
scenarios.
Top 100 Customers as a Calculated Table
There are many examples that a business considers top 10 or top 20
customers and filter down the whole dashboard and set of reports only for
them. Usually, the main reason is that the top 10, 20 customers will bring
the majority of revenue to the business. Fortunately, there is a TOPN
function in DAX that helps us to build such calculations. TOPN function
returns a table. With TOPN, we can choose how many rows we want in the
result set and the expression to be applied for ordering rows.
In this example, I want to show you how to use a calculated table to
generate a list of the top 100 customers. As a business requirement, I want
to visualize the total revenue from the top 100 customers and compare it
with the total revenue of the whole business. There might be different ways
to calculate and visualize it, but I want to do it with a calculated table as a
sample scenario.
Summarize
Summarize is a DAX function that generates a grouped list from a table.
Summarize works similar to Group By in T-SQL. So if I want to create a
table with CustomerKeys and their total sales amount, I can write this
expression:
Customer Sales = SUMMARIZE(FactInternetSales,FactInternetSales[CustomerKey], 'Total Sales',
SUM(FactInternetSales[Total Sales]))

Here are details about parameters I passed in the expression above to the
Summarize function:
First parameter: Source Table. FactInternetSales is the source
table that I want the group by (summarize) operation to be
applied on it.
Second Parameter: Group by Column. CustomerKey in the
FactInternetSales table is the column that I want to use as the
key for grouping.
Third parameter: Output Column Name. I named the output
calculated column name as Total Sales.
Forth parameter: Output Column Calculation. Here I write the
calculation for the output column, which is simply the sum of
the Total Sales Column.
So, as a result, I will have a table with CustomerKey and Total Sales.
TOPN
Now that we have a list of customers with their total sales, it is easy to get
top 100 customers. I can use a TOPN function like this to create another
calculated table (I could do this example with only one calculated table
instead of two, but I only did it with two tables to help you understand the
logic better);
Top 10 Customers = TOPN(100,'Customer Sales','Customer Sales'[Total Sales],DESC)

And expression above means:


First parameter: Number of rows to return. 100 for top 100
customers.
Second parameter: Source Table. Customer Sales is the source
of this operation which we want to fetch top 100 customers
from it.
Third parameter: Order By Column. I want to order the table
based on the Total Sales of each Customer.
Forth parameter: Order By expression (ASC, or DESC). To
get top 100 customers, I have to order it by Total Sales DESC.
and here is the result:
I also renamed the Total Sales column to Top Customer Sales (as you see in
the screenshot above).
Now I can build a report in Power BI to show the difference between Total
Sales and Top Customer Sales:
Great, We’ve used calculated tables to get some insight into the top 100
customers and compare it with the total. There are many other cases that
you can implement using the Calculated Table. Later in this book, you will
see an example of a date dimension created using the calculated table.

Limitations
The calculated table's very first limitation is memory. This limitation is also
an advantage, on the other hand, because the in-memory structure makes
these calculations fast.
The other limitation which I like to mention at this stage is: Not Inheriting
Formatting.
By not inheriting formatting, I mean the calculated table doesn’t inherit
format from the source table. In some complex scenarios where the
calculation comes from many tables, that might not be necessary. But for
our simple role-playing example above; If my original date dimension has
some formatting configuration. Such as setting DateKey to a “Do Not
Summarize” or some other configuration, then I would like to see the same
in the calculated table fetched out of this.
The formatting applied on the calculated table columns also will be
overwritten after each change in the DAX expression.
Chapter 4: Measure vs. Calculated
Column: The Mysterious
Question? Not!

Despite all articles, blog posts, and videos on DAX Measures and
Calculated columns, I still hear that people ask what the difference between
Measure and Calculated Column is? What situation should we use each of
these? On the other hand, what is the difference between creating a column
here or in Power Query? The chapter “M or DAX that is the question” in
this book explained situations that you need to use Power Query or DAX.
In this chapter, I will explain the difference between DAX
Calculated Column and Measure.
Read this chapter If You have any of
Questions Below
This chapter is written for you; if you have any of the below questions;
What is a Calculated Column?
What is Measure?
When should I write a calculated column or measure?
What is their difference in Performance?
What are operations that I cannot do with these?
And many other questions about the difference between these
two types of calculations in DAX.
What is a Calculated Column?
A calculated column is a column like any other column created in the table.
However, the result of a calculated column is coming from calculating an
expression (DAX). Usually, the calculated column leverages a DAX
expression that applies to every row in the dataset, and the result will be
stored in the new column.
Example: Profit as a calculated column
Consider a table that has sales and costs information. Calculating Profit in
such a table would be simply deducting costs from sales for every row. So
this basically would be a calculated column.

Expression:
Profit = FactInternetSales[SalesAmount] - FactInternetSales[TotalProductCost]

Row by Row Calculation: Row Context


One of the fundamental concepts about the calculation that you apply in the
Calculated Column (In the majority of the cases, not always); is that the
calculation evaluates one row at a time. Or, in other words, row by row
calculation. In the below table; you can see the calculation result for every
row stored in the new column;

Row by row calculation called Row Context in DAX terminologies.


Stored in Memory
The calculated column stores the values in memory. The calculation
happens at Refresh time, and the result will be held in the memory.
This means that the more calculated column you have, the more memory
consumption you will end up with, and your refresh time will be longer.
However, many calculations are not complex, so your refresh time might
not be affected too much.

Calculated Column highlights


Based on the above explanations, here are highlights of a calculated
column;
Row by row calculation: Row Context (usually, not always)
Stored in the memory (consumes RAM)
calculated at the time of refreshing the report (either scheduled
basis or manual)
What is Measure?
A measure is usually a calculation that works on an aggregated level basis.
This aggregation can be as simple as a sum of sales or a little bit more
complex, such as calculating monthly average sales in a rolling 12 months
period. Measures have dynamic nature. They affect a subset of data from
one or more tables. Hence, the subset of data can be changed through the
filters applied in the Power BI Report; the calculation will have to be
evaluated dynamically. So Measures are not pre-calculated; they will be
calculated on the fly when adding them to the report.
Example: Sum of Sales
Measures are usually aggregations. A very simple aggregation we can use
as an example is the sum of sales.

Aggregation can be done with several functions in DAX, such as Sum,


SumX, Average, Calculate, and heaps of other aggregation functions. Now,
let’s answer the most critical question:
How to see the Value of the Measure?
Measures are calculated on the fly. This is, in fact, one of the most
conceptual differences between a measure and a calculated column. How
can you see the value?! The answer is by putting that into a report!
If I drag the measure above in a report as a card visual, then I would get a
result;
When there is no filter applied in the report, this will return a total of
$29.36M. However, if I add a slicer in the report and select a value in it, I’ll
see a different result;

The measure calculation only shows me the sum of sales for 2007, which is
$9.79M.
Filter Context
Measure evaluates on the fly. If there is a slicer value for 2007, the
calculation will be done on the subset of data for 2007. If there is a table in
visualization somewhere that slices and dices the data by Education
category, the measure will take that into account. We can then say this;

Measure evaluates the value based on the subset of data


selected by filters, slicers, or slicing and dicing components
of visuals in the report. This filtered dataset, called Filter
Context.
Filter Context is a combination of all filters that affect the calculation of
measure.
Measures do not consume RAM; they consume
CPU
based on what you’ve learned above, measure calculation is done on the fly.
This means to measure value is not stored in the memory. The measure will
not consume Memory or RAM at all. On the other hand, Measures consume
the CPU because their calculation should be done right when visualizing it.
If you change a filter or slicer, the evaluation should be done again. Because
the response time should be fast, then this calculation happens by CPU.
What is the side effect?
Suppose you have many measures in your report, and their calculation is
also complex calculation, then with changing every filter or slicer. In that
case, you end up with many rounding circles, which shows the CPU is
desperately working hard to calculate all values.
Measures highlights
Based on the above explanations, here are highlights of a Measure;
Calculated based on all filters: Filter Context (usually, not
always)
It is not stored and is not pre-calculated
Calculated on the Fly when you put it on a report page when
you change a slicer, filter, or click on a column chart or any
other visual to highlight and it affect this measure’s value.
It consumes the CPU for calculation.
When to use Measure, and when to use
Calculated Column
Now that you know about these two types of calculation, we come to the
critical question: When to use which? Do you need a Measure for your
analysis or a Calculated Column? The answer to this question is depends on
what you want to calculate? This is an important question that you should
be asking yourself when you want to create a new calculation:

Is the calculation row by row? or is it an aggregation? Is it


going to be affected by filter criteria in the report?

The calculated column is what you need if the calculation is row by row
(example: Profit = Sales – Cost, or Full name = First Name & ” ” & Last
Name).
If the calculation is an aggregation or it is going to be affected by filter
criteria in the report (example: Sum of Sales = Sum(Sales), or Sales Year to
Date = TotalYTD(….)), then Measure is your friend.
Let’s go through some examples;
Example 1: Calculating the age of customers
The age of customers does not change based on filters! It is only dependent
on one thing; the birthdate of the customer. In the customer table, you
usually have the birthdate as a field. So this calculation can be simply a
calculated column, which evaluates row by row for every customer.
Example 2: Calculating Sales Year to Date
The year-to-date calculation depends on the filter criteria in the report, and
also it is an aggregation. It becomes very complicated to calculate year to
date for all variations of fields (per day, per month, per customer, per
product, etc.). So this needs to be a Measure.

every time you put this measure into a report, it calculates based on the
filter criteria of the report;
Calculated Column or Power Query?
When it comes to calculating row by row, then Power Query is a better
option in the majority of the cases. You’ve learned in the previous chapters
about M or DAX and what scenarios you need to use each. Power Query
can implement calculated Columns (in the majority of the cases).

Measure: The Hidden Gem of DAX


You can do a Calculated column in the majority of the cases in Power
Query as well, and in fact, it is much better to do that in Power Query in
those cases. This means the hidden gem of DAX is Measure. Measure
calculation is dynamic, on the fly, and based on filters applied in the report.
The dynamic nature of measure calculation makes it the invincible feature
of DAX or Power BI. You have seen in the above calculation that Year to
Date value is showed by month. If you bring Day value in the table, then
this calculation will evaluate daily and works still perfectly fine;
If you do it on a quarter level, the year to date calculation evaluates on the
quarter level;
This Dynamic nature of Measure calculation in DAX is something that you
cannot find in many tools. That is why Measures are so commonly used in
DAX. 70% of your time when you write DAX is used for writing measures,
if not more!

Summary: Calculated Column vs.


Measure in a nutshell
Let’s wrap up it all and go through a comparison of these two types of
calculations in DAX;
Hopefully, this chapter helped you to understand the difference between
these two types of calculation.
Chapter 5: Power BI DAX Back to
Basics: Scalar Vs. Tabular
Functions

DAX is the analytical language in Power BI. Learning this language,


however, comes with some difficulties. Part of that challenge is the way that
functions work in DAX. Learning the output of functions is a crucial
element of knowing how and where you can use them. In this chapter, I’ll
explain two types of DAX functions and ways to use them.

Scalar Functions
Scalar function in a function that returns one single value. This value can be
of any data type; Date, Numeric, Text, etc. But it is always one single value.
One of the most basic and straightforward functions in this category is
SUM.
Consider the measure below:
Sales = Sum(FactInternetSales[SalesAmount])

This calculation will return one single value. It depends on where you use it
in the report actually, but here you can see that it returns the total sales:

Measure Sales return one single value


If you use it in a table, however, you will see multiple results. But in fact,
that is one result, per the filter combination applied in the table.

SUM function returns one single value as a result, based on the filter applied.
We have many Scalar functions in DAX. Here are a few examples:
SUM/Average/Min/Max
SUMX/MinX/MaxX/AverageX/CountX
LastDate/FirstDate
Calculate
Related

You can use these functions directly in a Measure or Calculated Column.
The result of a Measure or Calculated Column should be one single value.
If these functions are used in a Measure, you will see the measure's value in
the visual. If they are used in a calculated column, you will see the values in
every row of the table;

The calculation above returns one single value per row in the Customer table.

Tabular Functions
Some functions return a table as the output, not a single value, a whole
table. The table can have multiple columns, or just a single column depends
on the function used. But it would be a table structure with multiple values
in it.
One of the most simple tabular functions is ALL. The All is a function that
returns the entire table without any filters applied (if just the table passed as
the input with no changes).
Copy of Customer Table = ALL(DimCustomer)

The expression above, as a Table, will return the below result;

ALL returns a table as the result


There are many tabular functions in DAX. Here are a few;
ALL, AllExcept
RelatedTable
SamePeriodLastYear
DatesBetween/DatesInPeriod
Summarize/GroupBy
TreatAs
….
You can use these functions mainly in a calculated table.
Tabular functions can be used directly in a Calculated Table.

Miss-Use of the Functions


So far, everything seems simple. The first problem appears when you want
to use a function in a place that you shouldn’t. For example, if you use a
scalar function to build a calculated table! Or use a tabular function to
return the main result of a DAX measure!
Scalar Function to Create a Calculated Table
This won’t work. A function that returns one single value cannot build a
table.

Scalar function cannot be the main output of the calculated table.

If you do this action, you will get the error saying: “the expression specified
in the query is not a valid table expression.”
That is because the Calculated table expects a table expression, which only
comes from tabular functions.
Tabular Functions to Return the output of a
Measure or Calculated Column
Another miss-use of the functions is when you use a tabular function
directly in a measure or calculated column to return the output.

Tabular function cannot be used to generate the main output of a measure or calculated column.

If you do this action, you will get the error “The expression refers
to multiple columns. Multiple columns cannot be converted to a scalar
value.”
This is because the function returns a table, and the measure expects a
single value.

What can You DO?


DAX is a language of nested functions. One function can be an input of
another function. So, you can use scalar functions to build a calculated
table, or you can use a tabular function to create a measure. You need to
know how to do it. Here is the guidance.

Using Tabular Functions in Measures


although you cannot use the tabular function result as the main result of the
measure, you can use that as an intermediate result inside a scalar function.
The expression below is calculating the sales of the same period last year;
Same Period Last Year =
CALCULATE(
SUM(FactInternetSales[SalesAmount]),
SAMEPERIODLASTYEAR(
FactInternetSales[OrderDate].[Date]
)
)

The expression below is written as a measure, yet, you can see that I have
used the SamePeriodLastYear in it, a tabular function.

Tabular function can be used inside a scalar function as a table expression parameter.
As you can see in the above screenshot, the result of the
SamePeriodLastYear (which is a tabular function) is used as the 2nd
parameter of the Calculate (which is a scalar function). And because the
measure's main output comes from the Calculate function, it works
perfectly fine.
Using Scalar Functions in Calculated Table
You can use the same approach and cascade scalar functions inside a tabular
function.
GroupBy - with aggregation = GROUPBY(
DimCustomer,DimCustomer[EnglishEducation],
"Row Count",
COUNTX(
CURRENTGROUP(),
DimCustomer[CustomerKey]
)
)

The expression above uses the CountX, a scalar function, inside the
GroupBy as a parameter. And the GroupBy is a tabular function. If you look
more in detail, you will also see that the CurrentGroup function is another
tabular function nested inside the CountX.

Scalar function used as a parameter inside a tabular function


The critical understanding from the examples above is that functions should
be used when their output type is expected.

How Should I Know Where to Use Each


Function?
This is a very fair question. Always look at the definition of the function, or
use the MSDN Docs. For example, here is the definition of the SUMX
Function;

Sometimes input parameters and output type are understandable from the function definition in the
Editor.
The Docs would also guide you to the same thing;

https://docs.microsoft.com/en-us/dax/sumx-function-dax[https://docs.microsoft.com/en-
us/dax/sumx-function-dax]
Not all functions have a perfect definition guide, but most of them have it.
Restrictions
Some functions can be used only in a specific context. For example, The
Calculate returns a scalar value, but it cannot be used inside a GroupBy
function. That is the limitation of the GroupBy function.

calculate function is not allowed as the expression for the GroupBy function.
You will find restrictions like these in some functions. However, mostly you
will find the docs that explain the limitation.

Check out the Docs to find out if there are any restrictions.
Exceptions
Some functions are neither tabular nor scalar. They don’t return an output.
For example, the CrossFilter function changes the behavior of a relationship
and can be used only inside a Calculate Function.

Summary
Understanding DAX requires you to change your mindset from
programming languages or even expression languages. The difficulty is
mainly understanding the filter context. However, another part is
understanding the output type of each function. You should know how and
where to use tabular or scalar functions in DAX. In this chapter, you learned
that you could nest these functions inside each other in the right way, but
always keep an eye on restrictions and exceptions.
Chapter 6: DAX Variables: Better
Readability, Consistency, and
Performance in Power BI
Calculations

Have you ever had a scenario that you need to use part of your calculation
multiple times? You might go and create a table or column for that and then
re-use it. However, there are times that you just need that calculation to be
re-used multiple times within one place. DAX variables can help you with
that. DAX variables are also helpful to make the performance of the
calculation better. This chapter will explain the DAX variable, scenarios of
using it, and how it can improve your Power BI calculations.
Re-Using Part of the Code
It sometimes happens that you need to re-use part of the code. Consider the
example below:
Adjusted Budget =
IF(
SUMX(
FactInternetSales,
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)
>
SUMX(
FactInternetSales,
FactInternetSales[UnitPrice]*FactInternetSales[ExtendedAmount]
),
SUMX(
FactInternetSales,
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
),
SUMX(
FactInternetSales,
FactInternetSales[UnitPrice]*FactInternetSales[ExtendedAmount]
)
)

The expression above is hard to read and also has some repetitive sections.
Let me mark them for you for better understanding:
We have two main parts in the expression above: A and B. Each of those is
doing a calculation. Now, with the markings above, reading the expression
is much simpler. The whole expression means this:
=IF(A>B, A, B)

All the above expression says that if A is greater than B, return A,


otherwise B. Now it is much simpler to read it because we split the
repetitive parts into sections. That is what the DAX variable does for
expressions.

DAX Variables
You can define a DAX variable with VAR (not case-sensitive), and then re-
use it as many times as you want through the same expression. Here is for
example, how I define a variable for A:
Adjusted Budget =
var A=SUMX(
FactInternetSales,
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)

Variables can be defined in any of the calculation objects: Column, Table,


or Measure

The expression above is not yet a complete one, and if you try something
like that, you will get an error. Defining the variable is part of the operation.
The other part is to return something. That is what we do using
the RETURN keyword.
Adjusted Budget =
var A=SUMX(
FactInternetSales,

FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)
return A

This expression just defines a variable and returns it. We don’t use the
expression defined within variable more than once, but still ok.
You can define more variables by adding more VAR to the statement. Here
is what our expression looks like using the variables:
Adjusted Budget =
var A=SUMX(
FactInternetSales,
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)
var B=SUMX(
FactInternetSales,

FactInternetSales[UnitPrice]*FactInternetSales[ExtendedAmount]
)
return
IF(A>B,A,B)

Variable makes your code more readable


and more consistent
The example above clearly shows how variables can make your code more
readable. Instead of having an expression long and uses many repetitive
parts, you can define the repetitive part of the expression once and re-use it
as many times as you want. When you define a part of the expression once
and re-use it multiple times, your code will become more consistent and
easier to maintain.

Variables are better for performance


Variables are not just good for readability; they are also good for
performance. In the expression below: the calculation for part A has been
done twice, same for part B:

However, if you define the part as a variable, then calculation happens once,
the result stored in the variable and re-used multiple times. This would
perform much faster than re-calculating it.
Anything can be stored in a variable:
Table or Value
Another good thing about the variable is that you can even store a table in a
variable. Like below:
var _allSalesTable=ALL(FactInternetSales)
var _totalmargin=SUMX(
_allSalesTable,
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)

As you can see, the outcome of the ALL of the FactInternetSales is stored
in a variable. This is a whole table stored in a variable and can be used in
other places.

Variables can be created inline: Scope


A variable definition should not always be the start of your DAX code or
even in the central part. It can be somewhere inline in another function. The
expression below shows another way of writing for the last expression you
have seen in the above;

This also means that variables have a scope in which they operate. If you
define the variable within the SUMX expression, then the variable cannot
be used outside of that part. If you define the variable at the beginning of
the main script's expression, it can be used anywhere in the same
expression.

Variables vs. Measures


One of the questions you might have now is that; sometimes, for re-using
an expression, you create a measure for it and then use that measure in the
next expression. How is that different from a variable?
Measures are global; Variables are local
Measures are global and can be used in any other measures in the same
Power BI file. However, variables are local, can be used only in the
expression in which they are defined.
Variables are better for performance
Because of how a variable is calculated, it would perform faster than using
a measure. If you define a variable, the calculation for that variable is done
once. However, if you create measures and then re-use measures multiple
times in an expression, that measure calculation is done multiple times.
A workaround is to create a measure and then define a variable to
materialize that measure in your expression. Like in the below example, I
have created a variable from the Sales measure:

Variables can store more than just a single value;


they can keep a table
Another benefit of using a variable is that you can store a whole table in a
variable. In a measure, you can return one single value.

When Should You create a variable?


You might ask: OK, I understand what variable is, but I cannot understand a
scenario to use it, or where in my DAX calculations should I change and
add a variable? That is an excellent question. Here are my rules of thumb
for creating variables:
If you use a part of your expression more than once
If the expression is hard to read.
If the calculation performs slow, and within that expression,
there are re-usable parts.
Summary
Variables, in my opinion, are the hidden gem of DAX expressions in Power
BI and any other tools that use DAX. Using variables, you will have a
better code. Your code would be more readable, more consistent, easier to
maintain, and most importantly, performs faster.
Chapter 7: Caution When Using
Variables in DAX and Power BI

Variables in DAX are helpful in both readability and also the performance
of your code. However, there are scenarios that you have to be careful when
you use variables. Because variables are stored, they might return a
different result if you had that definition in a measure. Let’s see an example
in this chapter.

Variables in DAX
You can define a DAX variable using the VAR statement and then use it in
a RETURN statement or even in another variable through that expression.
Here, for example, you can see a use case of the variable:
The above is an example of the “right” usage of the variable. Variable can
be used mistakenly in the wrong situation, though. Let’s see an example.

Calculating a Value Before Filtering


One of the most common mistakes for using variables is in a scenario that
you calculate the value before the custom filter is applied. Let’s assume you
want to calculate the same period last year's sales amount. The calculation
is typically like below:
Sales SPLY =
CALCULATE(
SUM(FactInternetSales[SalesAmount]),
SAMEPERIODLASTYEAR(DimDate[FullDateAlternateKey].[Date])
)
For the expression above, you don’t need a variable, but let’s say even for
that expression, if you decided to create a variable for the expression part of
it, it looks like below;
Sales SPLY using Var =
VAR _sales=SUM(FactInternetSales[SalesAmount])
return
CALCULATE(
_sales,
SAMEPERIODLASTYEAR(DimDate[FullDateAlternateKey].[Date])
)

As you can see in the below screenshot, the result is wrong! The result is
similar to the sales amount of each month! And that is wrong.
Why?
In DAX, variables are calculated within the scope in which
they are written. And then, their value is stored and re-used
in the rest of the expression.

This means that when we create the variable as VAR


_sales=SUM(FactInternetSales[SalesAmount]), the expression runs on the
filter context of the visual, which is the month in which the calculation is
evaluated. As a result. For each month, the value of _sales would be the
sum of the SaleAmount column in that month, then the rest of the
expression uses the stored result from that point onward.
Because the variable's value is stored, it is better that you calculate it
considering all the filters that you want to apply.
In this case, the context of the filter which we are trying to add is
the SAMEPERIODLASTYEAR(DimDate[FullDateAlternateKey].[Date]),
and we want the variable to be calculated using this filter context.
So calculating the variable in this scenario before
the CALCULATE statement makes it wrong. You either have to not use a
variable here for this scenario or use it in the context of that filter, which is
possible with the change in SCOPE of the variable;
Sales SPLY using Var - scoped =
CALCULATE(
VAR _sales=SUM(FactInternetSales[SalesAmount])
return
_sales,

SAMEPERIODLASTYEAR(DimDate[FullDateAlternateKey].[Date])
)

This expression is using the variable inside the context that it should be
calculated, and as a result, it returns the correct output;

Another Example
The example you have seen is more like a “learning” example because you
won’t create a variable usually for such a simple statement. I used that
example to explain to you what is the problem, and how to solve it. Now,
here is another example, which makes sense more;
Then this would be the wrong usage of variables for it:

Wrong Use of Variables


The expression below returns a different result. All the variable values are
calculated outside of the CALCULATE expression (And the filter
of SAMEPERIODLASTYEAR).
The Right Way
The expression below, however, is correct. The variables are used in the
scope of the context of the filter needed to be applied:

Here is the result and comparison of the two different expressions:


Summary
You might say that there are other ways of writing this expression without
the need for variables, and you are right. However, the purpose of this
chapter was to teach you that although variables can be used anywhere,
their result might not always be the same. Because they are evaluated in the
context in which they are written. The scope that you write the variable is
important and should be used cautiously.
Part 2: Aggregation and Iterators
Chapter 8: SUM vs. SUMX; What
is the difference between the two
DAX Functions in Power BI?

Sum and Sumx are functions that are often considered to be misleading for
many Power BI users. As both functions are doing the aggregation, it seems
confusing the actual difference between these two. There are many blog
posts and articles about each function. This chapter is explaining the
difference between these two functions.

SUM: Aggregation Function


SUM is a simple aggregation function. It summarizes a value based on a
filter context. For example, if I have a measure like:
Sum of Sales = SUM(FactInternetSales[SalesAmount])
This measure is simply calculating the summarized value of the
SalesAmount across the entire fact table when there is no filter selected.
And if I have a filter somewhere in my visualization, then it will calculate
the sum of the filtered context;

All other aggregation functions also work the same; Average, Min, Max,
Count, etc. Now let’s see when SUM functions fall short.

SUMX: Some of an Expression


Let’s now calculate the sum of margin, which is: the sum of sales minus
cost. This calculation considers that we do NOT have a column as a margin
in our model, and we do not want to create that column. Let’s see how it is
possible through a measure to calculate the sum of Margin.
Margin calculation is: SalesAmount – TotalProductCost
But you cannot write a measure like below:

When you start writing that measure, you don’t even get the DAX
intelligence for the second part of your expression:

DAX intellisence doesn’t show the TotalProductCost column from the


FactInternetSales table, but the column is definitely in the table. The
intellisence (the popup when you write DAX code) in DAX is always
reliable. If it doesn’t allow you to write something somewhere, it means
based on your expression or functions that you’ve used; it is probably not
the right place to write it. So why cannot you write such a simple
statement?
Because SUM only accepts a column name as input. Here is the structure of
the SUM function;
As you can see, the input is just one column name. It cannot be one column
minus another one; that means an expression. So, what is the way to do it?
One way is to use multiple sum functions, such as below code:
Sum of Margin = SUM(FactInternetSales[SalesAmount])-
SUM(FactInternetSales[TotalProductCost])

And it would work. However, for long expressions, this way of writing will
become hardly readable. If you add one Sum in front of every column
name, you may end up with expressions such as below;
A measure with few SUMs =
if((SUM(FactInternetSales[SalesAmount])

-SUM(FactInternetSales[TotalProductCost]))
/SUM(FactInternetSales[OrderQuantity])
>SUM(FactInternetSales[ExtendedAmount])
,SUM(FactInternetSales[ExtendedAmount])
-SUM(FactInternetSales[SalesAmount])
,SUM(FactInternetSales[OrderQuantity])
*(SUM(FactInternetSales[UnitPrice])
-SUM(FactInternetSales[UnitPriceDiscountPct])))

It looks scary. Well, there is another way; use SUMX. SUMX is the sum of
an expression, the X at the end of this function is for eXpression. This
function gives you the sum of any expression. Here is the way to use it:
SumX(<table name>,<expression>)

For SUMX to work, you need to specify a table name. When you use SUM,
you do not need a table name because one column only belongs to one
table. But when you use SUMX, you may write an expression that uses
columns from other tables. In the example for Margin, both columns are
coming from the same table; FactInternetSales. So, our expression would
be:
Sum of Margin = SUMX(
FactInternetSales,
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)

SUMX is the sum of an expression, but SUM is just


summarizing values of one single column.

SUMX is an Iterator Function


How is SUMX behind the scene doing the calculation? SUMX will go
through every single record of the input table and run the expression for that
record. It stores the result of that into temporary memory.
At the end of parsing the table and calculating all values for every single
row, it will summarize them all together because it is SUMx, releases the
temporary memory, and visualize the result;
Because of this ITERATION nature of the SUMX function, it is also called
as Iterator function. Other iterator functions are: AverageX, MinX, MAXX,
CountaX, etc.

Iterator functions are looping through all rows in the input


table and storing the expression result in temporary
memory storage. Finally, they apply the aggregation on the
temporary storage results, release the memory usage, and
visualize the calculation result.

One crucial understanding about SUMX is that SUMX uses memory


(temporarily, but still uses memory) for calculation. Another important
finding is that it calculates values row by row. If you run SUMX on a huge
table with a complex expression, you probably need to wait a bit for results
to come through.

The hidden gem of the SUMX; Table


Input
The example you have seen so far about the SUMX was an easy one, which
you could even write without SUMX (remember the way we did it with
multiple SUM functions). But the hidden gem of using the SUMX function
is not just the flexibility on the expression; it is also the flexibility on the
table input.
Let’s say you want to calculate the total margin in an expression. How are
we going to do that? Well, you may say we just use the same SUMX
statement that we have used so far, which gives us the result below;

But the expression above is not always giving you the total margin. If you
slice and dice it by a column, here is the result;
Filter context (or, let’s say, whatever filters the visual) will impact the
calculation result. So, when looking at the Bachelors' education category,
the sum of Margin for that is not the total margin; it is just the sum of
margin for that category.
ALL is an exciting function, which we will have a separate chapter about it
in this book. I can use the ALL function to give me the entire table
regardless of the filter context; this is what my expression and the result
would look like:
Total Margin = SUMX(
ALL(FactInternetSales),
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)
How does this work? ALL is a function that returns a table as output.
SUMX is a function that gets a table as input. So they can work with each
other nicely! ALL can be the input table of the SUMX function. Nesting or
cascading functions and tables into each other is something that happens
very often in DAX. Because ALL is a function that passes the entire table
regardless of the filter context, we get the full FactInternetSales table with
no filters, and the result would always be the total margin.
You may think, what is the usage of such a thing? Well, you can use it to
calculate the percentage of the margin for each education category. Here is
how it works:
Any TABLE can be the Input for SUMX
It is not just the ALL function that can be the input for SUMX. You can also
use any other functions that return table or any other tables as the input for
the SUMX. For example, the expression below is giving us the Filtered
result of the FactInternetSales table, when the Education category is “High
School”;

In this example, the FILTER function is used as the input for SUMX to give
us the calculation result only on a filtered dataset.
Sum of Margin for High School = SUMX(
FILTER(
FactInternetSales,
RELATED(DimCustomer[EnglishEducation])="High School"
),
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)

This can be done with other functions as well. Here, for example, I used the
CalculateTable function to do the filtering:
Sum of Sales by Customer = SUMX(
CALCULATETABLE(
FactInternetSales,
DimCustomer[EnglishEducation]="High School"
),
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost])

The result is:

SUMX is a function that you can set an expression and a


table as the input. Having the ability to change both the
expression and the table (as a filter or something else)
makes this function a generic function in DAX.

Summary
Sum and SumX are both functions calculating aggregation. However, the
SUMX calculates the aggregation on an expression resolved from a table
that can be dynamically calculated. SUMX is a generic and powerful
function, so we see the usage of that a lot in DAX. One thing to remember
is that SUMX, like any other iterator function, is consuming temporary
memory storage and doing the calculation one row at a time, then
aggregates it.
Chapter 9: Calculate Totals in
Power BI: Using Iterators in DAX

The total value that you see in a table is not SUM of all values in that
column; it is, in fact, the calculation when there is no filter. This, however,
might not be the calculation that we want sometimes. We might want this
value to be the sum of values of that column in the table visual. This
chapter will show you an easy method to calculate the total using Iterator
functions in DAX.

Defining the Problem


I wrote an article about using DAX calculations to calculate the lost vs. new
customers using Power BI[https://radacad.com/lost-customers-dax-
calculation-for-power-bi]. That article showed a result like below:
The calculation works perfectly fine, as you can see in the row level.
However, it doesn’t work at the total level. The count of the total is always
zero in the above expression. The sample above works with the calculations
below:
Sales measure:
Sales = SUM(FactInternetSales[SalesAmount])

Sales last period measure:


(The value of this measure changes with the selection of period slicer –
period slicer comes from a What If parameter)
Sales Last Period = CALCULATE(
[Sales],
DATESINPERIOD(
FactInternetSales[OrderDate].[Date],
LASTDATE(FactInternetSales[OrderDate].[Date]),
-1*[Period Value],
MONTH)
)
New Customer measure:
New Customers = IF([Sales Last Period]=[Sales],1,0)

Lost Customer measure:


Lost Customers = IF([Sales Last Period],0,1)

To learn more about the details of the calculations above, read my


article here[https://radacad.com/lost-customers-dax-calculation-for-power-
bi].

Iterator Functions in DAX


Iterators in DAX are functions that iterate through all rows of the given
table, apply the expression, and then aggregate the result. One of the known
functions in this category is SUMX. Because an iterator function goes
through every row and applies the transformation, the result is materialized
(temporary) before aggregating it. That causes the totals to be the actual
sum (or other aggregations) of values in a column.
So using SUMX, I can add a calculation like this:
New Customers Total Count =
SUMX(
DimCustomer,
[New Customers]
)

All you see in the above expression is that I am saying calculate the [New
Customers] measure value once for every row in the customer table. This
result will be stored in the temporary memory and then at the end
summarized (because we are using SUMX).
The same method can be used for Lost customers too:
Lost Customers Total Count =

SUMX(
DimCustomer,
[Lost Customers]
)

Testing the result


If you add the two measures with the above calculation in the visuals, you
can see that they show the aggregated total values:

because in this report, I am also using what-if parameters, so it changes


with the change of the period value.

Summary
SUMX and Iterators are only one way to help you create the totals, but it is
not the only way. Sometimes, you might find the performance of iterator
functions slower than other methods.
Chapter 10: Showing Ranking in a
Visual in Power BI using RANKX
DAX function

If you want to show the ranking in a Power BI visual, one way is to use a
visual supporting that, such as a Ribbon chart[https://radacad.com/ribbon-
chart-is-the-next-generation-of-stacked-column-chart]. Another way, which
is a more common way, is to write a calculation for rank, and RANKX is a
DAX function that can help you with that. In this chapter, I explain how
that works.

RANKX DAX Function, How does it


work?
RANKX is a Scalar function in DAX. It means it just returns one value. It
cannot be used directly to create a table unless it is combined with tabular
functions.
RANKX provides the rank as a number based on an expression. Here is the
syntax of using this function:
RANKX(<table>, <expression>[, <value>[, <order>[, <ties>]]])

The table and expression are the required parameters. The rest are optional.
Table: The table (or virtual table) is used as the source of items
for the ranking.
Expression: The expression that the ranking is calculated
based on it. This DAX expression should return a single scalar
value.
value (optional); scalar expression
order(optional); Based on what order the ranking is calculated.
Default is descending.
ties(optional); What should happen if there is a tie
Using RANKX as a Measure
If you want to use it in a measure (usually when you want the ranking to be
calculated dynamically), there is a little trick.
Let’s assume we want to have the ranking in the visual below based on the
Sales measure (which is Sum(FactInternetSales[SalesAmount]).

Table visual without ranking


If you use RANKX as below, it is not going to work as expected;
RANKX Wrong Way =
RANKX(
DimProduct,
[Sales])

Color is a field in DimProduct, and you may think the table parameter of
the RANKX should be DimProduct, but that leads to all ranks to be
calculated as 1!

Ranks miscalculated in Power BI


Even if you change the table to FactInternetSales, you will get the same
result. The reason is that RANKX will evaluate the rank based on the
values generated for the table parameter. The table parameter still considers
the visual filter.

The TABLE matters


When the visual is filtered by color, the table will already be filtered by that
color. And the rank of the color in that single color is always one! The trick
is to run the expression for all values. A function similar to the ALL can be
helpful.
The correct way of calculating the rank in a visual that we want to rank it
based on the color is to do it for all of that Color column;
Color ranked by Sales =
RANKX(
ALL(DimProduct[Color]),
[Sales]
)
This would generate the correct ranking as below;

Using RANKX in a Power BI measure


If you want to show the ranking on a visual with more than one column,
then your table parameter should include that too;
Color and size ranked by Sales =
RANKX(
ALL(DimProduct[Color],DimProduct[Size]),
[Sales]
)

Here is the result;


Ranking for more than one column
The above works if the two columns are from one table. Of course, if the
two columns are from different tables, you will get an error as below;

All column arguments of the ALL/ALLNOBLANKROW/ALLSELECTED/REMOVEFILTERS


function must be from the same table
In a case like this, you can use a function that creates a table of the
combination, something like CrossJoin.
Color and Education ranked by Sales =
RANKX(
CROSSJOIN(
ALL(DimProduct[Color]),ALL(DimCustomer[EnglishEducation])
),
[Sales]
)

CrossJoin is, of course, not the only way to produce this result; it is just one
way of doing it.

calculating rank in Power BI when table columns are from two different tables
Think of all tabular functions when you want to write the table parameter
here. They can be most helpful.

Dealing with TIES


An important consideration when you are doing the ranking is what
happens when there is a tie?
TIE is when two values in the table generate precisely the same number as
the expression and will end with the same rank. Below is an example of
TIE;

TIE when using RANKX in Power BI


When there is a tie, the rank for both items would be the same (example; 8,
10, or 13 in the above). But you can choose what the next rank is going to
be.
SKIP
This means if there is a tie (for example, two items with the rank of 10), the
next rank value would skip these ranks and start from 12 (10+2(number of
ties)). This option is the default tie condition. And it is what you see already
in above as a result.
DENSE
If there is a tie (for example, two items with the rank of 10), the next rank
value would start from the next rank regardless of the tie, and would be 11.
Here is an example result of ranking with dense tie condition;
Customer Name ranked by Order Quantity - DENSE =
RANKX(
ALL(DimCustomer[FullName]),
[Order Quantity],,,Dense
)

and the result is shown here;

dense tie condition with RANKX in Power BI

Summary
RANKX is a scalar DAX function in Power BI, which can be very helpful
when calculating rank as a value in a Power BI visual. The critical
consideration for ranking is to pass the table parameter value correctly. You
can also choose what happens when there is a tie.
Chapter 11: Generating Row
Number in Power BI Visualization
Using DAX

You can generate a row number using Power Query.


[https://radacad.com/create-row-number-for-each-group-in-power-bi-using-
power-query] That method is suitable for pre-calculating row numbers in
the table. However, sometimes, you want to calculate the row number in a
Power BI visualization based on something dynamic. That is where DAX
comes in handy. Let’s see how this is possible.

Sample model
I have a simple model with three tables below;
I also have a couple of measures for the SalesAmount for each of the fact
tables;
Internet Sales = CALCULATE(SUM(FactInternetSales[SalesAmount]))
Reseller Sales = CALCULATE(SUM(FactResellerSales[SalesAmount]))

Now imagine that we want to have a visualization like below that shows all
the products, and their Internet Sales;
In the above visualization, I want to calculate the row number based on
Internet Sales.

Row Number Using RANKX


RANKX is a handy function in DAX for many scenarios. One of those is to
calculate the row number based on an expression. RANKX has two
mandatory parameters and some optional parameters. The required
parameters are; the table or column in which we have the list of all items,
and then the expression which you calculate the index based on it.
If I want to calculate a row number based on the Internet Sales, my
expression can be like below;
Row Number = RANKX(
ALL(DimProduct[EnglishProductName])

,[Internet Sales])

The expression above returns the row number as an index descending by


the value of Internet Sales for each EnglishProductName.
That was easy.

Understand How to Use RANKX for Row


Number
Now let’s see how you can do that in your Power BI solution. Let me guide
you through the parameters you need to set for the RankX function;
1st parameter: Table
The first parameter should be a TABLE. This can be a physical table in
your model or a virtual table (a table generated by tabular functions). You
notice that I used ALL(EnglishProductName). You might wonder Why
ALL is used?
Imagine we are looking at one row in the table visual. If you pass just the
table name in the first parameters, it means only the rows in that table that
fit into the current filter context, which means the current product only. So
you are ranking a single product, not the whole table. The result would
always be 1!

If you use the ALL, even if you are in the current row, the indexing will
happen on the entire list, leading to the correct result.
Can’t I use a column only?
No. This parameter has to be a table. A column is not representative of a
table.

What if I say the ALL of the table?


That is a possible option, but you have to consider having a column in the
visualization with the same granularity as the table. The
EnglishProductName is not that column because we have multiple rows in
the DimProduct table with the same EnglishProductName (their color or
other columns might be different). This means an expression like below:
Row Number = RANKX(
ALL(DimProduct)
,[Internet Sales])
Will not show the value you expect in the below context;

But it works perfectly in the context of ProductKey;


The reason is that we have the index done at each row-level (when we said
ALL(DimProduct)), and ProductKey is the only column that has a unique
value per row.
What if I have more than one column?
You can have combinations of columns in your row number calculation.
here is an example of how it works for the EnglishProductName, and Color;
Row Number = RANKX(
ALL(DimProduct[EnglishProductName],DimProduct[Color])

,[Internet Sales])

You can have multiple columns inside the ALL function. The result is as
below.
Is ALL the only function that works?
No. you can use many other functions. The main thing to remember is that
you need to use a function that gives you a list of unique combinations of
values you want to create the index.
2nd Parameter: Expression
The second important function is the expression. The row number is based
on what value? Internet Sales or Reseller Sales? The below example returns
a row number based on Reseller Sales.
Row Number = RANKX(
ALL(DimProduct[EnglishProductName])
,[Reseller Sales])

and here is the result;


There are other parameters for this function too, but explaining them will be
outside of the topic of this chapter which is focused only on the row
number.

Summary
RANKX is a function that you can use to calculate the row number
dynamically in a measure in Power BI. If you want to calculate the row
number, not dynamically, I strongly recommend doing it in Power
Query[https://radacad.com/create-row-number-for-each-group-in-power-bi-
using-power-query] or the data source.
Part 3: Filter
Chapter 12: FILTER Function in
DAX and Power BI: Apply Custom
Filter to Calculations

You can apply filtering to visualization elements. However, sometimes


filtering has to be done on specific calculations. This can come in handy,
especially when comparing values of other items with particular items. In
this chapter, I'll explain how to use the FILTER function in DAX to apply a
custom filter in the calculations of Power BI.

FILTER Function in DAX


The FILTER function is often used to filter rows of a table. The Filter
function keeps the columns untouched, and it just reduces the number of
rows based on filter criteria. The Filter function is tabular (it returns a table
as a result). It can create a calculated table or as a table input parameter for
other functions. Here is the syntax of using this function:
FILTER(<table>,<filter>)
As you can see, the syntax is straightforward, including just two
parameters;
table: the table which we want to be filtered.
Filter: the condition(s) of filtering. This is an expression with a
Boolean result (means has to return true or false)
Samples of using Filter as a table
expression
Here are some samples of using the Filter function as a calculated table.
Let’s start with a most basic example. If we want to have a subset of the
DimProduct table for those products whose Color is Red, the expression
can be as below;
Filter 1st example = FILTER(
DimProduct,
DimProduct[Color]='Red')

The Color field in the DimProduct will be filtered to only include Red as
below;
Filter function in DAX used to filter a table with one condition in Power BI
Note that DAX is not case-sensitive, “Red” and “red” would be the same. If
you want to make it case-sensitive, you can use exact match functions, as I
explained in later chapters of this book.

Filter function with multiple conditions


A filter expression can have multiple conditions too. You can separate them
using AND or OR functions, or their equivalent operators (&& and ||);
Filter 2nd example = FILTER(
DimProduct,
DimProduct[Color]='Red'
&&
DimProduct[SizeUnitMeasureCode]='CM')
The “&&” in the expression above means AND. The output will be only
products with their color as red and their SizeUniteMeasureCode as CM.

Using filter function with multiple conditions in Power BI

Filter does not change columns


The Filter function only reduces the rows of a table. It will not change the
number of columns or the order of it. You can use other functions such as
the SELECTCOLUMNS or the ADDCOLUMNS or any other table
manipulation functions to do that.
Filter 3rd example =
var filtered=
FILTER(
DimProduct,

DimProduct[Color]='Red' &&
DimProduct[SizeUnitMeasureCode]='CM')
return
SELECTCOLUMNS(
filtered,
'Product Name',
DimProduct[EnglishProductName]
)

In the expression above, the result of the FILTER function (which is a


virtual table) is used as an input table parameter for the
SELECTCOLUMNS function. As a result, we have a table with one
column: name of the products whose color is red and their size unit is CM.

Using filter function inside other functions in Power BI and DAX

Using Filter function in a measure


Like many other tabular functions, the typical use case scenario is to use
them inside a measure. Using a tabular function inside a measure allows us
to create virtual tables dynamically based on the filter conditions in the
visualizations in the table.
For example, I can use the below code to get the Sales of all products that
their color is red OR their size unit measure is CM.
Sales of Red OR CM =
var filtered=
FILTER(
DimProduct,
DimProduct[Color]='Red' || DimProduct[SizeUnitMeasureCode]='CM'

)
return
CALCULATE(
[Sales],
filtered)

The “||” in the expression means OR.

Filter function used in a DAX measure in Power BI


The filtered expression result is used as an input to the Calculate function to
provide the sales of the filtered data.

Summary
The FILTER function in DAX is a simple function to use for filtering rows
of a table. This function does not change the columns (unless used as an
input of column manipulation functions such as SELECTCOLUMNS or
ADDCOLUMNS). The filter function requires a table input and an
expression. The expression should return true or false and can include
AND/OR functions or operators. Like many other tabular functions, the
main benefit of this function is when used to create a virtual table in a
measure expression.
Chapter 13: Now You See Me! Use
cases of the ALL DAX Function in
Power BI

Among all the functions in DAX, the behavior of the ALL function still
seems mysterious for many. Many users don’t use it and write a highly
complex calculation for a scenario that only a straightforward expression
can do the same job. Some users use it but don’t exactly know how the
function works, get unexpected results, and call it an error. This chapter will
explain what the ALL function is, how it can be used, and what are use
cases of using such a function in DAX and Power BI.
Prerequisite
The dataset for this model is the AdventureWorksDW2012 Excel file,
which you can download from the book’s code file. The tables used in this
example are DimCustomer, DimProduct, FactInternetSales.
What is the ALL() Function in DAX?
Nothing is better than an example to understand the behavior of the ALL
function. Let’s see how it works in action; I’ve created a Measure using the
ALL function. ALL function accepts a table as input, and
ALL( <table name or column name>, [Column name 1],[column name 2], …)

The output of the ALL function is a TABLE, and you cannot use it in a
measure. As you can see in the below screenshot; if I create a measure with
ALL, I get an error saying; The expression refers to multiple columns.
Multiple columns cannot be converted to a scalar value.

As the output of ALL function is a table, then you have only two ways to
use it in DAX:
Using ALL directly in Calculated Table
As the output of the ALL function is a table, it can be used directly in
creating a calculated table. For example, All used with a table name will be
an exact copy of that table.

Or, if you use all with only one or more columns, then you get a table with
a distinct combination of those column values;
ALL(FactInternetSales[SalesAmount]) will return only 42 rows, which is
the distinct values in the SalesAmount Column,
However, If ALL is used with a combination of columns. Such as three
columns below, then the combination would be distinct;

Using the ALL function in the Calculated table, give us one of the most
common use cases for the ALL function:

Role-Playing Dimension using ALL and


Calculated Tables
You can create role-playing dimensions, copies of an existing dimension
(such as the Date dimension). I have written about this scenario in earlier
chapters of this book.
Using ALL as an Input for Other DAX
functions
If ALL cannot be used directly in a Measure, then no dramas. It can be used
as an input parameter for other functions. In DAX, many functions accept a
table as input. All those functions can accept ALL as their input parameters.
For example, SUMX is a function with a table parameter; in our case, this
can be a table generated by ALL as a function.

As an example, this is one sample usage of ALL and SUMX:


Measure = SUMX(
ALL(
FactInternetSales
),
FactInternetSales[SalesAmount]
)
SUMX is just one of the DAX functions that accepts a table as an input
parameter. There are many other functions such as Calculate and many
other functions in the same category. Combining the ALL with other
functions and using that in DAX measures are the most common methods
of using this function. But before going further, let’s explain something
essential about the ALL function.

ALL Ignores the Filter


In addition to returning a table as the output, ALL will also ignore any
filter(s) applied to it. What does that mean? It means if you have a
visualization that is filtered by something, then ALL won’t care! It will just
act like there is no filter there. Here is an example:
Total Margin = SUMX(
ALL(FactInternetSales),
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)
Sum of Margin expression is as below:
Total Margin = SUMX(
FactInternetSales,
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)

and Total Margin expression is as below:


Total Margin = SUMX(
ALL(FactInternetSales),
FactInternetSales[SalesAmount]-FactInternetSales[TotalProductCost]
)

As you can see, the only difference is the usage of ALL in the Total Margin
expression. The output value is also different. The total Margin in each row
is the same value; $12,080,883.65, like the margin, is never filtered by
Education, or let’s say like ALL function ignores the filter applied.
Common Use Case for ALL: Calculating
Percentage
One of the most common use cases for using ALL is calculating the
percentage of a measure. The trick is to calculate that value once without
the ALL. And once with the ALL. And then divide one by the other! Just
for an instant, think how you would do this calculation if there were no
ALL function? How would you find out the total margin when the
Education category already filters the margin? This is the power of the ALL
as a function to give you such a combination.
ALL and Calculate
ALL can also be used as an input for the Calculate function. The second
input is a filter, and a table function acts as a filter. In our case, ALL is a
filter function that DOES NOT filter! No matter where you write the
calculate function, whatever filter applied will be ignored when you put an
ALL function.

Use Case for ALL function: Controlling


the Interaction
Suppose with selecting an item in the slicer; you don’t want the values in a
specific measure in table visual to change. Well, now that you know about
the ALL, it seems possible how to do it.
Measure Slicer As you
Date Filter Sales Date can see
Product Filter Sales Product in the
Multiple Filter Sales Date and Product above
screens
hot, the Date Filter Sales is only impacted by CalendarYear Slicer. The
Color Slicer only impacts the Product Filter Sales; however, both are
affected by the Multiple Filter Sales measure!
Here is the script for the Date Filter Sales Measure for example:
Date Filter Sales = CALCULATE( SUM(FactInternetSales[SalesAmount]),
DATESBETWEEN(DimDate[FullDateAlternateKey],
FIRSTDATE(DimDate[FullDateAlternateKey]),
LASTDATE(DimDate[FullDateAlternateKey])
),
ALL(FactInternetSales)
)
As you can see, an ALL function has been used. However, because there is
another filter in Calculate (DatesBetween), the expression will consider the
intersection between these two filters. As a result, in this case, ALL will
ignores any filters coming from any other tables except the DimDate. There
will be a chapter with more explanation of this particulate example.

The Table which ALL is applied to is


Important
It is not just important to use the ALL function. It is also essential to use it
on the right table needed. For example, if I want the Total Sales regardless
of any filters, I can write:
Total Sales = CALCULATE(
SUM(FactInternetSales[SalesAmount]),
ALL(

FactInternetSales
)
)

However, if I am interested in achieving the total sales of all customers but


then allow all other filters to pass, I can write:
Total Sales Customer = CALCULATE(
SUM(FactInternetSales[SalesAmount]),
ALL(
DimCustomer
)
)
In the second expression, I used ALL(DimCustomer), and in the first one, I
used ALL(FactInternetSales). It means that the first expression will ignore
ANY filters. However, the second expression only ignores filters coming
from the DimCustomer.
The ALLExcept Function: An Extension
Sometimes you want to ignore the filter coming from all columns in the
table, except for one or more columns. Using ALLExcept is a good option
for such scenarios. Let’s say that We want the filter from Gender to pass
through, but the filter from all other columns to be ignored. We can write an
expression using ALLExcept, and use the Gender in it as below;
Total Sales Except Gender = CALCULATE(
SUM(FactInternetSales[SalesAmount]),
ALLEXCEPT(
DimCustomer, DimCustomer[Gender]
)
)
Summary
Because the functionality of the ALL seems like magic, so I titled this
chapter as; Now you see me! Use cases of the ALL function in DAX and
Power BI. Although it looks elementary, the ALL function is one of the
most important and commonly used functions in DAX. the main
functionality of ALL is to ignore filters from one table. You can use the
ALL function inside other functions as the table input. There are many
examples, such as percentage calculation and overwriting the interactions of
measures, that can be done simply using the ALL function. If you haven’t
used this function before, consider it from now on seriously.
Chapter 14: How to Use the ALL in
a DAX Expression in Power BI

The previous chapter was about the ALL function in Power BI and how it
helps work with filters in your report. However, more clarity on this
function would always help. This chapter is explaining that in detail.

Why ALL?
The ALL is a handy function in DAX that ignores the filters. Because in
Power BI, measures are always affected by the filters coming through
visuals (filter context), sometimes IGNORE these filters, can be very useful
on many occasions.
For example, you can use ALL in an expression like below to get the total
SalesAmount regardless of filters applied in other visuals or slicers;
Sample Model
To understand the rest of the chapter, I start showing you the data model I
am working with, which is as below:
Sample Report
I also have the below report as a sample:
In the above screenshot, you can see that the Sales measure’s value is
affected by three filters: Color from DimProduct, EnglishPromotionName
from DimPromotion, and EnglishEducation from DimCustomer. Although
they are not defined as a filter, two of them are slicers, and one is a column
in the table visual. Still, they are filtering the values calculated by the
measure.

ALL Ignores the Filter Coming from One


Table
There are many variations that you can use the ALL function. one is to
ignore filters coming from only one of the tables:
Sales All Customers =
CALCULATE([Sales],ALL(DimCustomer))
The above expression ignores the filters from EnglishEduction (a column
from DimCustomer) but accepts the filters from the other two tables. As a
result, this measure would return the total sales for all customers that can
still be sliced and diced by other tables.
ALL can be used to get the total and calculate the percentage based on that.
If you change the input table of ALL expression to ALL(DimProduct), for
example, then it will get filtered by the DimCustomer, and DimPromotion,
but not by DimProduct. in other words; use the table that you want to
calculate the total of it in ALL as the input.
Sales All Products =
CALCULATE([Sales],ALL(DimProduct))

The calculation above gets filtered by the Promotion and Education, but not
by the Color (from DimProduct).

Ignoring Filters from Two Tables


You can use ALL to ignore the filters coming from more than one table.
One way to achieve this is to use multiple ALL inside the calculate
expression like below;
Sales All Customers and Products =
CALCULATE(
[Sales],
ALL(DimCustomer),
ALL(DimProduct)
)

The expression below won’t accept any filters coming from the
DimCustomer or DimProduct tables.

Ignoring filters from All tables


In some scenarios that you want to calculate the total regardless of selecting
any filters or slicers, you need to ignore filters coming from all the tables.
There are two common approaches for that;
Using All for the Fact Table
If you use the Fact table inside the ALL expression, it will ignore all the
filters coming from other tables. The fact table would be the table that your
value is coming from;
an expression such as below will give us that result;
Sales All Fact Table =
CALCULATE(
[Sales],ALL(FactInternetSales)
)
The expression above ignores filters coming from the FactInternetSales
itself, which then means ignoring filters from all the dimensions around it.

Using ALL without Input Parameter: Ignore


Everything
Another approach is to use ALL without any input table or parameters, just
as ALL(). This will ignore everything, which can be a good option if your
calculation’s value comes from multiple tables and you don’t want any
filters to affect it.
Sales All =
CALCULATE([Sales],ALL())

Other Variations
Other variations of using ALL, such as ALLExcept or using ALL with
other functions, can help ignore some filters and accept custom filters.
Chapter 15: Removing the Total
Value for a Column in the Table
Visual of Power BI Using
ISFILTERED

Table visual is one of the most commonly used visuals. You can turn off the
total row (when it won’t make sense to have the total) entirely. However,
you cannot turn off the total for some columns and keep it working for
others. Using a DAX function, you can, however, do this easily. Let’s see
how it is possible.

Total Row in the Table Visual


In the table visual in Power BI, you get the total row by default;
You can disable the total row entirely using the Format tab of the visual and
then under the Total.
There are scenarios that you want to only turn off the total value calculation
for one of the columns. Turning off the entire total row might not be the
best option in those cases. For example, the total for SalesAmount in the
above example is good, but the total for the List of FullName values is
unnecessary. The List of FullName values shows the three custom names
under each category, and when we are in the total row, that means everyone.
So it is better to get it removed. I show you two ways of removing this total
value.

The DAX Way: ISFILETERED


DAX has a handy function that can help you determine if the value showed
in a visual, filtered by a field/table, or not. The function is called IsFiltered.
This DAX function gets the field/table name as the input and returns a true
or false value, meaning that if that field filters the context in which the
calculation is running or not.
ISFILTERED(<table or column name>)

To show you how this function works, I write a measure like below:
Is Filtered = ISFILTERED(DimCustomer[EnglishEducation])

If I add this into my table visual, I can see when this function returns TRUE
or FALSE
Because the EnglishEducation field filters the table visual in the above
screenshot, the ISFILTERED returns true for every row in the table.
However, the total row is NOT Filtered by the EnglishEducation, and that
means returning False.
The ISFILTERED function is beneficial in many scenarios of writing DAX
expressions. In our case, for removing the total value from a specific
column, it can be used simply by using the field that filters all other fields.
In my case, All I need is to check if the EnglishEducation is filtered or not
and then use it in the measure calculation of “List of FullName values” (this
measure is, by the way, a quick measure created by a concatenated list of
values.[https://radacad.com/quick-measures-in-power-bi-you-dont-have-to-
write-dax])
Here is my changed version of the DAX expression with ISFILTERED in
it;
As you can see, I wrapped the measure’s value inside an IF statement like
this:
IF(
ISFILTERED(
<column or table name>
),

<the result you want to show for the table rows - not the total>
)

This would give me something like this:

The above IF statement only uses the expression, and the what-if true, part
of the IF., the what-if false part of it, is not used because it is optional, and
when not provided, the default is blank.
If you ever want to provide something else as a result of the total row, you
can then use the what-if false part of the if statement like below;
IF(
ISFILTERED(
<column or table name>
),
<the result you want to show for the table rows - not the total>,
<the result you want to show for the total row only>
)

in my case, I change it to All Customer text;


And this is what the results look like now:
Formatting Visual Way; The Easy Way,
but Limited
If you are looking to remove the total for a specific column and you don’t
want to spend time fixing your DAX codes, there is an easier way. You can
go to the Format tab of the visual, Under Field Formatting, select the field
that you don’t want the total for it, and then make the below changes:
Set the Apply to values to Off, Apply to total to On, and then set the font
color to white (or something that makes the total look blank)

This method of visual formatting is more straightforward. However, it


comes with caveats;
If your Field values have specific formatting, then this
formatting might change that.
If you are using themes or any other background colors, you
need to configure the Font color and Background color
respective to that after every change in the theme.
You cannot replace the total value with a different text or
something like what you have seen in the DAX.
Summary
I’m sure there will be an option in the table visual at some points to turn off
the total for each field. However, until that time, this might help you to do
what you want. On the other hand, this helped you to understand how the
ISFILTERED DAX function works and use it in countless different
scenarios in your Power BI solution.
Chapter 16: Find The Data Value
using LookupValue DAX Function
in Power BI; Simple and Useful

LookupValue function is neither a new function in DAX nor a complex one.


However, in my training courses and presentations, I figured out that a few
users are still aware of this function. This is a straightforward yet powerful
function in DAX, particularly helpful whenever you look to find a data cell
or a value somewhere in the data table in Power BI. Let’s see how this
function works.
Sample Dataset
If you want to download the dataset used for this example, download it
from this book’s code file.
For this example, I am using only one table: DimEmployee, which looks
like below:

LookupValue: Find the Value


LookupValue is a function in DAX that can be used to find a value in a
specific cell in a data table. This function can be used with the below
syntax:
LookupValue( <result column>, <search column>, <search
value>, [<more search columns>, <more search values>]…,
[<alternate result>])

Each parameter is defined below:


Result Column: The column that we want to get as the output
of this expression.
Search Column: which column are we searching into it to find
the value?
Search Value: What is the value we are searching for it in the
specified column?
Alternate Result: What value should be used if the search
value isn’t found in the data table.
Let’s see that through an example:
Let’s say I am looking for the employee with the EmployeeKey 31. Here is
the code for it:
Employee 31 =
LOOKUPVALUE(
DimEmployee[FirstName],
DimEmployee[EmployeeKey],
31
)

I used the expression above as a Measure and showed it in a Card visual in


Power BI. You can see in the expression that I used three parameters:
If you have a database developer background, you can read the expression
above as a T-SQL code like below:
Select FirstName
From DimEmployee
Where EmployeeKey=31

If you don’t have a database background, this is what the code is doing:
The expression will find the data row with the “31” value in the
EmployeeKey column and then return the value of the FirstName column.
What if the value not found?
If the value is not found, then the alternate result will be returned by default
blank.
Employee 31 =
LOOKUPVALUE(
DimEmployee[FirstName],
DimEmployee[EmployeeKey],
2222222,
"Not found!"
)
What if multiple values as the output?
The LookupValue function works best when you have only one value
returned. If you have multiple values, it will either return the result of
<alternate result> if supplied; otherwise, it will return an error.
Employee 31 =
LOOKUPVALUE(

DimEmployee[FirstName],
DimEmployee[MiddleName],
"R",
"Not found or Multiple results"
)
You can add more criteria
If you have more search conditions, you can add them all by adding more
search columns and values.
Employee 31 =
LOOKUPVALUE(
DimEmployee[FirstName],
DimEmployee[MiddleName],
"R",
DimEmployee[LastName],

"Gilbert",
"Not found or Multiple results"
)
LookupValue Function is Often Used
Within Other Functions
Although, you can use the result of the LookupValue function as a measure
or column on its own. However, the majority of use cases of LookupValue
is where it has been used inside another function. Let’s say you are looking
for a value of a different column in a table when another column’s value is
equal to something, and then using the result, you want to apply some
filtering or other work.
Here is an example of the LookupValue function I have used in
my Dynamic Row-Level Securit[https://radacad.com/dynamic-row-level-
security-in-power-bi-with-organizational-hierarchy-and-multiple-positions-
in-many-to-many-relationship-part-2]y example:
In that example[https://radacad.com/dynamic-row-level-security-in-power-
bi-with-organizational-hierarchy-and-multiple-positions-in-many-to-many-
relationship-part-2], I fetched the user ID of the logged-in user using the
LookupValue function.

Summary
The LookupValue function in DAX is a very simple yet helpful way of
fetching the value of a column in a data table when other column’s values
are equal to something. You can read it as a select/where statement in T-
SQL, or similar to how VLookup somehow works in Excel. The primary
usage of this function is when it is used inside other functions as an input
parameter. However, this function can be used on its own to return a value
for a visualization.
Chapter 17: The IF and Filter are
Different! Be Careful (DAX)

DAX has many functions to write conditional expressions. For example,


you might want to calculate the sum of sales amount for all “Red” products.
You can achieve it using SUMX or Calculate and functions such as IF or
Filter to write a conditional expression for product color to be equal to
“Red”. At first, you might think these functions will have the same result
set, but there is a difference that should not be overlooked. This chapter will
explain what type of problem might happen if you don’t use these functions
wisely.

Brief of Functions
IF
“IF” is a conditional filtering expression function for DAX. You can write a
conditional expression including the Then and Else part of it. It simply
works with this syntax;
IF(<conditional expression>, <what happens if true>, <what happens if false>)

Filter
“Filter” is a function that filters data set based on a custom filter. For
example, you can filter only products with a “Red” color. Here is an
example Filter expression;
FILTER( <table>, <filter condition>)

Sample Data Set


For this example, you need to bring FactInternetSales, and DimProduct into
your Power BI Model. The relationship between these tables automatically
should be detected by Power BI. It should be based on ProductKey between
two tables. Here is how the relationship looks like;

Conditional Sum
There are multiple ways of calculating conditional sum in DAX. You can
use SUMX or CALCULATE. Both of these functions calculate an
expression (In this case, it would be the sum of sales amount from
FactInternetSales) based on a filter (which would be our conditional
expression to find “Red” products). I will use SUMX in this example, but
the same concept applies to Calculate function as well. Here is how you can
use SUMX for calculating the sum of “Red” products;
Method 1 – SumX with FILTER
I can use the SUMX expression and filter the data set to be only “Red”
products in the first method. Create a new Measure in FactInternetSales
with this expression;
Sum of Red Products - With Filter = SUMX(
FILTER(FactInternetSales,
RELATED(DimProduct[Color])='Red')

,FactInternetSales[SalesAmount]
)

As you can see in the above expression, I have used a simple FILTER
function to filter everything in FactInternetSales when the Color or product
is “Red”. I have used the RELATED function because Color is a column in
DimProduct, and Related Function goes through the relationship from
Many (FactInternetSales) to One (DimProduct) and allows us to do the
filtering based on a column in a related table.
Method 2 – SumX with IF
We can achieve the same result with SUMX and IF together. In this case,
the condition comes as an IF statement in the expression part of SUMX.
Here is the new measure’s code;
Sum of Red Products - With IF = SUMX(
FactInternetSales,
IF(RELATED(DimProduct[Color])='Red',
FactInternetSales[SalesAmount],
0)
)

In this expression, instead of filtering data with the FILTER function, I have
used a conditional expression to identify if the product's color is “Red” or
not. If it is “Red”, then I use SalesAmount for sum calculation. Otherwise, I
use zero (means don’t summarize for other product colors).
Method 3 – Calculate with Simple Conditional
Expression
There are many other methods of calculating the conditional sum, but just
adding this one because it looks different; If I use Calculate Function with
simple expression for checking the color of the product as a new measure;
Sum of Red Products - Calculate Simple Expression = CALCULATE(
SUM(FactInternetSales[SalesAmount]),
DimProduct[Color]='Red'
)

Writing DimProduct[Color]=”Red” in this way is similar to writing a


condition for every result set. The final result will be the sum of Red
Products.
Testing Results – Similar
If you bring both measures in Power BI as a Table Visual, you will see the
result of both are identical, and it will show you the total sales amount for
products with “Red” Color correctly;

Different Results
The result for the measures is perfectly similar; however, if you use one of
these measures for a data set, you will see the result of the data set is
different, which significantly changes the outcome. For example, if you use
“Sum of Red Products – With Filter” only in a table with “Color” from
DimProduct, here is what you will see:

If you use “Sum of Red Products – With IF” only in a table with “Color”
from DimProduct, you will see the different results;

In both cases, the total is similar. However, the table with a FILTER
measure will automatically filter the data set and only show the result set
for RED products. The second table with IF measure will display all
products with zero in front of all colors, except Red. These two are VERY
different from the user's point of view, while the final total value is similar.
The reason is that IF apply a conditional expression on the result set, where
FILTER works differently and filters the data set to the custom filter
expression. Notice that we don’t have any Visual, Report, or Page Level
filters applied in this example. Filtering happened automatically because of
the FILTER function.
If you bring the last method’s result into a table (Sum of Red Products –
Calculate Simple Expression), you will see the calculation happens on
every row in the result set. It won’t filter the data set, but the filter applies to
calculating the final result for every row.

Which One to Use?


Like many other situations; It Depends! Are you only interested in the final
result (sum of sales amount for “Red” products in this example)? If yes,
then they are all similar. However, if you want to show a detailed view of
records, then the FILTER function will also filter the data set, which might
not be something you like. In those cases, IF would give you the correct
response. If you want to calculate the percentage for each row, the Calculate
method might generate a more reliable result. Notice that there is nothing
wrong with these functions; they are working as they should. However, Not
knowing their actual behavior might cause some confusion for you and your
users. So use them wisely and don’t overlook their differences.
Chapter 18: Overwrite Interaction
of Power BI with DAX

This chapter will explain one method of writing DAX expressions that
overwrite how Power BI visuals interact. You will learn how to write a
DAX expression that some filters affect on that, some not. Let’s see how the
method works.

Filter Context in DAX


It is impossible to start explaining this method without talking about filter
context. Filter context is everything you used for filtering and slicing, and
dicing in the report. For example, create a Power BI model based on
DimDate, DimCustomer, DimProduct, and FactInternetSales. Ensure that
you have only one active relationship between FactInternetSales
(OrderDateKey) and DimDate (DateKey). Create a Measure with DAX
code below:
Sum of Sales Amount = SUM(FactInternetSales[SalesAmount])
Now create a report with a Table of Full Name (from DimCustomer), Sum
of Sales Amount. Also, create two slicers; one for Calendar Year and
another for Product Color.

In the above screenshot, you can see that result of Sum of the Sales Amount
is not always the same value. IT DEPENDS! It depends on what filter you
have selected or what values you have sliced and diced. For example,
Highlight numbered 1 shows the sum of Sales Amount for product Color
Blue, the Calendar Year 2008, and Customer’s Full Name “Aaron Collins”.
While the highlight numbered 2, shows the sum of Sales Amount for the
Year 2008, and color Blue, but for all Customers. What you see here is
Filter Context.
Filter Context is the combination of all filters, slicers, highlight, slicing, and
dicing applied to a report or visual. Filter Context for number 1 in the above
image is product Color Blue, the Calendar Year 2008, and Customer’s Full
Name “Aaron Collins”.
Everything in DAX resolves based on Filter Context and Row Context.
However, there are some ways to control the context. Controlling the
context means controlling the interaction of visuals. In the above example,
with any change in the slicer, filter context changes, and the result of
Sum(SalesAmount) also changes. However, if we write a DAX expression
that doesn’t change with selecting a slicer, that means we have controlled
the context. Let’s look at some examples.

Total Sales Regardless of Filters


For example, you can create a measure that returns the total sales amount
regardless of what is selected in slicers or filters, irrespective of the filter
context. For this, you can use either Iterator (SumX, MinX, MaxX, etc.) or
Calculate function. Create measure below;
Total Sales = SUMX(ALL(FactInternetSales),FactInternetSales[SalesAmount])

In the above DAX expression, the ALL function will act regardless of
filter context. No matter what Filter context is, the ALL will return
everything, and as a result, SUMX will calculate the sum of SalesAmount
for all rows. Here is a screenshot of the report;

It doesn’t matter what filter you select or what slicer you click. The result
for the measure is always total value. Now let’s control the context a bit
differently.
Total Sales Filterable Only by Date
Selection
Let’s take one step forward with bringing one selection criteria in the
measure. For this measure, we want to create a Total Sales that can only be
changed when a date selection happens (Year in our example), but nothing
else.
Because we need multiple filters now, I’ll do it this time with a
CALCULATE function to specify various filters. Here is the code:
Date Filter Sales = CALCULATE( SUM(FactInternetSales[SalesAmount]),
DATESBETWEEN(DimDate[FullDateAlternateKey],
FIRSTDATE(DimDate[FullDateAlternateKey]),

LASTDATE(DimDate[FullDateAlternateKey])
),
ALL(FactInternetSales)
)

In the measure above, we have two filters; ALL(FactInternetSales) and


DatesBetween(). DatesBetween brings everything from the FirstDate to the
LastDate. FirstDate and LastDate will depend on the date selection in the
slicer. As a result, DatesBetween will return the filter context of date
selection. However, everything else will be ignored by
ALL(FactInternetSales). The result will be a filter which is the junction of
these two filters. Here is the result;
You can see that the value in this new measure (Date Filter Sales) changes
by any selection in Calendar Year slicer, but nothing else. The result of this
measure will always be the sum of sales amount for all transactions in the
selected year. If nothing is selected in Year slicer, this column’s value will
be similar to the Total Sales Measure.
How if we want to enable multiple filters then? Let’s look at another
measure.

Measure Filterable with Multiple


Selections
Let’s go even one step further and add a measure that can only be affected
by selecting date and product slicer values, but nothing else. You know the
answer already, I believe. You just need to add one more filter to the list of
filters. I’ll do it this time with a RelatedTable function, but you can do it
with other methods as well. Here is the new measure;
Multiple Filter Sales = CALCULATE( SUM(FactInternetSales[SalesAmount]),
ALL(FactInternetSales),
RELATEDTABLE(DimProduct),
DATESBETWEEN(DimDate[FullDateAlternateKey],FIRSTDATE(DimDate[FullDateAlterna
teKey]),LASTDATE(DimDate[FullDateAlternateKey]))
)

The above measure is similar to the previous measure with only one more
filter: RelatedTable(DimProduct). This filter will return a subset of select
products. As a result of this measure, Product and Date selection will be
effective;

Summary
As you can see, simply with DAX expressions, you can control the filter
context. In other words, you can control the interaction in Power BI. Note
that you can write DAX expressions in many different ways. The
expression above is not the only way of controlling filter context. Iterators
and Calculate function can be very helpful in changing this interaction.
Part 4: Relationship Functions
Chapter 19: Get a field value from
a related table in Power BI: DAX
RELATED Function Explained

Sometimes, in Power BI, you need to access a field’s value from another
table that somehow is related to the existing table. You can use Power
Query transformations such as
combining Merge[https://radacad.com/append-vs-merge-in-power-bi-and-
power-query] with something else. However, this can be needed when you
write a DAX expression too. In this chapter, I explained a simple but
effective DAX function for this purpose; RELATED.

Understand the relationship


Before I talk about the function itself, I want to emphasize the need to
understand how the relationship in Power BI works. I have written many
blog articles (and videos) about this subject, here are some of those:
What is a Relationship?[https://radacad.com/back-to-basics-
power-bi-relationship-demystified]
What is the Cardinality of the Relationship?
[https://radacad.com/many-to-one-or-many-to-many-the-
cardinality-of-power-bi-relationship-demystified]
What is the Direction of the Relationship?
[https://radacad.com/what-is-the-direction-of-relationship-in-
power-bi]
Inactive relationship and what to do about it?
[https://radacad.com/userelationship-or-role-playing-
dimension-dealing-with-inactive-relationships-in-power-bi]
The model I am using in my sample has the relationships as below. It is not
a star schema[https://radacad.com/power-bi-basics-of-modeling-star-
schema-and-how-to-build-it], but it serves the purpose of explaining the
RELATED function.

Power BI sample model with relationships


In another view, here are the relationship’s details in the model above;
The relationship’s key columns in the sample Power BI model

RELATED DAX Function


The Related is a function in DAX that is very simple to use. This function is
a scalar function (It returns only one value) and gets one input parameter.
The result would be the value from that field in the other table based on the
relationship already exists in the model.
RELATED(<column>)

The only input parameter for this function is the column's name which we
want to fetch its value. Let’s see that as an example.

Sample of using the RELATED


Let’s say I want to add a column in the DimProduct table showing the
EnglishProductSubcategoryName. However, the
EnglishProductSubcategoryName exists in the DimProductSubcategory
table. If I add a column and try to write the expression below, it won’t
work.
EnglishProductSubcategoryName - wrong way =
DimProductSubcategory[EnglishProductSubcategoryName]

The expression above won’t work, and I will get an error, saying that:
A single value for column ‘EnglishProductSubcategoryName’ in table
‘DimProductSubcategory’ cannot be determined. This can happen when a
measure formula refers to a column that contains many values without
specifying an aggregation such as min, max, count, or sum to get a single
result.

You cannot access a field’s value from another table in a calculated column
Why can’t you write an expression that way? Because the
EnglishProductSubcategoryName in the other table has multiple values, not
one single. Your column expression should return one single value. The
EnglishProductSubcategoryName that is for this product (the current row’s
product). You can use a LookupValue function in DAX to retrieve the value
you want, but the solution is much simpler than using the RELATED
function.
Fortunately, in the model, there is a relationship between the two tables
based on ProductSubcategoryKey;
The existing relationship between the two tables
This means that the RELATED function can give you the value of any
column from the DimProductSubcategory table while writing a calculated
column in the DimProduct table. All you need as an input is the column's
name you want to pull the data from it.
Sub category =
RELATED(DimProductSubcategory[EnglishProductSubcategoryName])

The Related function fetches the value from another table based on the existing relationships in the
model.
The Related function goes through a one-to-many relationship and will give
you a value from the ONE side of the relationship and bring it to the
MANY side.
How the RELATED function works in Power BI and DAX

The RELATED can traverse multiple


relationships
The Related function does not only travel through one relationship. It can
go through all the relationships (as long as it follows the rule of returning
one value to the main table, which means it travels towards ONE side of
relationships). You can use the same approach to get the
EnglishProductCategoryName column from the DimProductCategory table,
even though there is no direct relationship between DimProduct and
DimProductCategory.
Category =
RELATED(DimProductCategory[EnglishProductCategoryName])
The result is the category name in the product table as another column;

The related function accesses the field’s value from tables even if the relationship is not direct
In the example above, the values of category names traveled through two
relationships, with just one mention of the RELATED function.
The related function can traverse multiple relationships
As you see, the Related function makes things far simpler than
LookupValue if the relationship already exists. There is, however, a
direction that the RELATED function won’t work on that.

When doesn’t the RELATED work?


The Related function pulls the values from the ONE side of the relationship
to the other side. This means a one-to-one relationship and a one-to-many
relationship work just fine with this function. But not the many-to-many
relationship.
Also, the one-to-many relationship only allows you to use the RELATED
when you are on the MANY side of the relationship, not the ONE.
The reason for all of these is that the result of the RELATED function is
just one value. When you want to use it on the MANY sides, then
multiple values are returned. The RelatedTable can be used in those
scenarios, which I will explain later.

In what situations the related function in DAX doesn’t work.


Using Related in Measures
You can use the Related function in the measures when necessary. Here is
an example; in the example below, I am using SUMX to get the sum of
sales for products with the color of Red. The column that I am calculating
the sum of it is in the FactInternetSales table, and the Color is in the
DimProduct table.
Sum of Sales for Red products =
SUMX(
FILTER(
FactInternetSales,
RELATED(DimProduct[Color])="Red"

),
FactInternetSales[SalesAmount]
)

There are, of course, much easier ways to write the expression above using
Calculate. However, I just wrote it using SUMX without the help of extra
measures to show you how the RELATED function can work in this
context. I have filtered the FactInternetSales table using the Color field in
the DimProduct table using the RELATED function used inside a FILTER.

The Related function can be used in a calculated column or a measure


Summary
The Related function in DAX can be used to fetch a value from a field of
another table. However, that table should be related to the existing table
somehow in the model. The relationship should be in a way that it returns
one value from that table per value in the main table. The Related function
can traverse multiple relationships in the model and can also be used inside
measures or other functions.
Chapter 20: Power BI DAX
RelatedTable Function: Get the
subtable related to the current row

Multiple functions can help when you work with tables that are connected
through relationships. One of these functions is Relatedtable. This function
gives you the subtable from the other table for all the rows related to the
current row. For example, calculate all the sales transactions (from the Sales
table) for the current customer (from the Customer table). In this chapter, I
explain how this function works.

Understand the relationship


Before I talk about the function itself, I want to emphasize the need to
understand how the relationship in Power BI works. I have written many
blog articles (and videos) about this subject, here are some of those:
What is a Relationship?[https://radacad.com/back-to-basics-
power-bi-relationship-demystified]
What is the Cardinality of the Relationship?
[https://radacad.com/many-to-one-or-many-to-many-the-
cardinality-of-power-bi-relationship-demystified]
What is the Direction of the Relationship?
[https://radacad.com/what-is-the-direction-of-relationship-in-
power-bi]
Inactive relationship and what to do about it?
[https://radacad.com/userelationship-or-role-playing-
dimension-dealing-with-inactive-relationships-in-power-bi]
The model I am using in this sample has the relationship as below.

sample data model

RELATEDTABLE DAX Function


In the previous chapter, you learned about the Related function and how to
use it. Similar to that function, the RELATEDTABLE function also works
with the relationship. However, unlike the other function, the
RELATEDTABLE returns a table as the output. That makes the
RELATEDTABLE function a tabular function. The returned table is a sub-
table of the given table for all records that match the key in the current row
of the current table. This is how the function works;
RELATEDTABLE(<tableName>)
The input table can be a table in your dataset, let’s say FactInternetSales. If
this function is run while we are at the row context of the DimCustomer
table, the output will be all sales transactions are related to that specific
customer. Let’s see that through an example.

Sample of using the RELATEDTABLE


Let’s assume that we want to add a calculated column to the DimCustomer
table and show the total sales amount for that customer. This is what the
DimCustomer table looks like;

Sample data of the DimCustomer table


There are different ways to calculate the total sales amount for each
customer, but I want to show you a method that uses the RELATEDTABLE
to teach you how to use this function.
To calculate the sales amount for each customer, we need first to find all
transactions for each customer. The sales transactions are in the
FactInternetSales table, and there is a relationship between the two tables.
We need a way that gives us the rows from the FactInternetSales for each
record in the customer table. Something like below;
how the RELATEDTABLE function works in DAX and Power BI
The RELATEDTABLE function will travel through the existing relationship
between tables, and will populate a list of rows (sub-table) from the given
table (in the case above; FactInternetSales) for each row in the table that we
call the function from it (in this case; DimCustomer).
This means our calculation can be like this:
Sales =
SUMX(
RELATEDTABLE(FactInternetSales),
FactInternetSales[SalesAmount]
)

In the example above, the RELATEDTABLE generates a table used as the


SUMX function input. Of course, the RELATEDTABLE can be used in
many other functions that expect a filter or a table expression, such as
Calculate.

RELATEDTABLE function used in a calculation in DAX and Power BI

The RELATEDTABLE function can


traverse multiple relationships
Very similar to the RELATED function, the RELATEDTABLE function can
traverse through multiple relationships. For example, Let’s say that I have a
third table in the model; DimGeography. DimGeography is related to
DimCustomer.
A model with multiple relationships
I can use the same calculated column expression to get the total sales for
each geography area;

The Relatedtable function traverse multiple relationships


The RELATEDTABLE function can also be used in measures similarly.
This function cannot be used directly in a measure because it returns a
table. You need to wrap it inside another function that accepts a table or
table expression.

Summary
The RELATEDTABLE function is working with existing active
relationships in the model. This function returns a table, which is the subset
of rows from the given table for the row context of the other table. This
function can traverse multiple relationships. This function can be used in
measures too, but as this is a tabular function, you need to wrap it in other
functions to return a scalar value.
Chapter 21: UseRelationship or
Role-Playing Dimension; Dealing
with Inactive Relationships in
Power BI

In a Power BI model, relationships are essential for passing filters. Filter


propagates through relationships. However, sometimes you create a
relationship between two tables, and the relationship is a dashed line. In this
chapter, I’ll explain everything you need to know about a dashed
relationship, or as it is called an Inactive relationship. I will present two
different methods that you can deal with this kind of relationship. So,
ready? Let’s go through it.
Why Relationships in Power BI?
The first topic to discuss is to understand why a relationship in Power BI is
essential? A relationship in relational database systems is essential to link
tables to each other, but in Power BI, the relationship also plays another
even more important role; Filtering.
To understand how the relationship works, let’s check this example:
I have a sample Power BI file getting data from the AdventureWorksDW
Excel file example, and I get information from two tables:
FactInternetSales, and DimDate. These two tables are NOT related to each
other at the beginning.

Let’s create a simple column chart with the SalesAmount from the
FactInternetSales table and the FullDateAlternateKey from the DimDate
table. Because the FullDateAlternateKey is a date field, Power BI brings the
default hierarchy. I’ll see the visual slicing and dicing data by the highest
level of the hierarchy, Year.
But wait, it isn’t slicing and dicing! It is showing the same SalesAmount for
every single year from 2005 to 2010! The value is very close to $30 million,
which is the total sales in my dataset. The fact is that the
FullDateAlternateKey field is NOT filtering the FactSalesAmount table.

Relationship Means Filtering


Now, let’s create the relationship between these two tables, based on the
OrderDateKey in the FactInternetSales table and the DateKey in the
DimDate table;
That’s it, let’s go and recheck the same visualization:

As you can see, the same visual, this time filters the sales by the date field.
Or better to say, DimDate can now FILTER the FactInternetSales table. All
of that because of the relationship. Without a relationship, we cannot filter
data across tables just by itself. You may need to do some DAX expressions
instead.

Relationship in Power BI means Filtering and the ability to


slice and dice a table by another table.

Now that you know relationships are for Filtering let’s check out what the
inactive relationship is.

Inactive Relationship
The type of relationship you have seen above is called an active
relationship. There is another type of relationship called Inactive. Let’s see
how an inactive relationship will be created. In the previous example, we
sliced and diced data by the OrderDateKey field because the field
connected through the relationship to the DimDate table. Now, let’s say we
want to slice and dice data by the ShipDateKey. The simple approach is to
create another relationship between the DimDate table and
FactInternetSales but this time to the ShipDateKey. Here is the result:
As you can see, this new type of relationship is different. It is a dashed line,
compared to the active, which was a solid line. This is an inactive
relationship. You can only have one active relationship between two tables.
Any other relationships will become inactive.

You can only have one active relationship between two


tables. Any additional relationships will become inactive.

An inactive relationship doesn’t pass filtering. It doesn’t do anything by


itself. I still see many people creating inactive relationships in their model,
thinking that just the inactive relationship by itself will do some filtering. It
doesn’t. If I use the FullDateAlternateKey from the DimDate table to slice
and dice the SalesAmount from the FactInternetSales table, which field is
used for filtering? The field used for filtering is the field used in the Active
relationship, of course. Here is a result for that (which is the same as what
you have seen in the previous example because the inactive relationship
doesn’t do anything. It is just the active relationship that passes the filter);

An inactive Relationship Doesn’t pass the filtering by itself.


It needs treatment!
Yes, the inactive relationship needs special treatment to work. Let’s see how
this can work. I explain two treatments for an inactive relationship; the
Role-playing dimension and UseRelationship method.

Role-playing Dimension
A dimension that acts as multiple dimensions is called the role-playing
dimension in the data warehousing terminologies. In the above example,
DimDate will play the role of Order Date in some scenarios, the role of
Ship Date in other scenarios, and sometimes the role of Due Date in other
times. I already explained a sample usage of Calculated tables in DAX to
implement a role-playing dimension in another chapter earlier in this book,
so let’s go through it very quickly here too.
One method to deal with the inactive relationship is to remove the cause to
create it! If having multiple relationships between two tables is causing the
creation of an inactive relationship, one way to avoid it seems to be creating
multiple instances of the same table. Then you would need only one
relationship, not more than that.
Let’s create a copy of the DimDate. One way to make the copy is to use a
Calculated Table with the ALL DAX function in it;
The ALL is a function that gives you the entire table. In this case, we are
creating a copy of the DimDate table and calling it ShipDate. Now you can
create a normal active relationship between ShipDate and the
FactInternetSales table (I have removed the inactive relationship from the
previous section);

And now, as a result, you have slice and dice by the ShipDate table as well
as the Order Date (or let’s say DimDate table);
The role-playing dimension is one of the ways that you can
handle an inactive relationship, but be careful of memory
consumption!

Copy only small tables


The role-playing dimension method is copying the table, and you will have
double-up memory consumption. The extra memory consumption can be
overlooked if the table is small. A Date table is a small table. For every
year, it is 365 rows, and for 20 years, it will be around 7,000 rows. It is very
small compared to a fact table with millions of rows. This solution is
suitable for small tables. But don’t use this method for big tables. If you
have a dimension table with 5 million rows and 30 columns, then the role-
playing dimension method means consuming the same amount of space
twice or three times or more.

Avoid role-playing dimension if you have a large


dimension. This method is only suitable for small tables.

UseRelationship Function in DAX


Another method to handle inactive relationships is to use a function in DAX
called UseRelationship. This DAX function is saying to Power BI that for
this expression, use this relationship, even if it is inactive. Let’s see how
this function works.
If we continue the same example of slicing and dicing by Ship Date and
assume that there is no Ship Date calculated table created, we can do it this
way; Create the inactive relationship between DimDate and
FactInternetSales again based on the ShipDateKey.

Now, let’s create a Measure in Power BI with the below expression:


Sales by Ship Date = CALCULATE(
SUM(FactInternetSales[SalesAmount]),
USERELATIONSHIP(
FactInternetSales[ShipDateKey],
DimDate[DateKey]
)
)

This measure calculates the sum of sales by ship date. The whole secret is
the usage of the UseRelationship function. This is a really simple function
to use. You need to provide two input columns to it, the two columns that
are two sides of the relationship. Their order is not important.
UseRelationship (<column 1>, <column 2>)

The critical tip to consider is that you HAVE to have an existing inactive
relationship for this function to work; otherwise, you get the error below:
An inactive relationship must exist; otherwise, the
UseRelationship doesn’t work.

One table filters the other table based on multiple


fields
The main benefit of using this method is that you can now have the
DimDate table to filter the fact table based on both ShipDateKey and
OrderDateKey at the same time, as illustrated below:
As you can see in the above screenshot, one date table filters the fact table
based on multiple fields. One is based on OrderDateKey, an active
relationship. And the other is based on ShipDateKey through the use of the
UseRelationship method in the measure.

This method doesn’t consume extra memory. However, you


do need to create a measure for every single calculation
with the UseRelationship function.

Summary
In this chapter, you learned about inactive relationships and how to handle
them through two methods; the Role-playing dimension and the
UseRelationship function in DAX. The role-playing dimension method is
good for smaller tables where the extra memory consumption is not the
issue. UseRelationship method, on the other hand, can be a good substitute
when the tables are bigger. There are other benefits, such as getting one
table filtering based on multiple fields at the same time as you’ve seen.
Chapter 22: DAX CrossFilter
Function in Power BI: Write the
Formula both-directional, but keep
the relationship single-directional

If you are familiar with relationships in Power BI, you know that there are
scenarios that you may need to change the direction of the relationship to a
both-directional. A both-directional relationship comes at a cost, which is
mainly the performance and ambiguity of the model. There is a way to
write a calculation in a both-directional way but keep the relationship still
single direction. This would help with the performance because the
performance impact will only happen when using this measure. In this
chapter, I explain how you can do that.

Understand the relationship


Before I talk about the function itself, I want to emphasize the need to
understand how the relationship in Power BI works. I have written many
blog articles (and videos) about this subject, here are some of those:
What is a Relationship?[https://radacad.com/back-to-basics-
power-bi-relationship-demystified]
What is the Cardinality of the Relationship?
[https://radacad.com/many-to-one-or-many-to-many-the-
cardinality-of-power-bi-relationship-demystified]
What is the Direction of the Relationship?
[https://radacad.com/what-is-the-direction-of-relationship-in-
power-bi]
Inactive relationship and what to do about it?
[https://radacad.com/userelationship-or-role-playing-
dimension-dealing-with-inactive-relationships-in-power-bi]
The model I am using in this sample has the relationships as below.

Sample model with multiple fact tables


I have chosen the model above to show some samples of filtering data of a
table by another table. As you can see, we have three fact tables in the
above model (highlighted), and all the relationships are single-directional.
CrossFilter DAX Function
CrossFilter function is neither tabular nor scalar function. It is a specific
type of function that changes the direction of a relationship. This function
cannot be used just by itself. It has to be used as the filter part of other
functions such as Calculate. Here is how the function works;
CROSSFILTER(<columnName1>, <columnName2>, <direction>)

Column1: The column on one side of the relationship


Column 2: the column on the other side of the relationship
direction
None: no filtering
Both; filtering will propagate both ways
Oneway; filter propagates from one side of the
relationship to the many side
Oneway_LeftFiltersRight; in a one-to-one
relationship, the left table filters the right table
Oneway_RightFiltersLeft; in a one-to-one
relationship, the right table filters the left table
The best way to understand a function is to learn it through an example, so
let’s check a couple of scenarios.

Changing the direction to both-directional


through DAX expressions
Let’s assume that a reporting requirement is to have a list of customers and
the sales amount related to them (coming from FactInternetSales) as below;
sample table visual
This works fine because the FactInternetSales table gets filtered by the
DimCustomer table;

the single-directional relationship between the two tables


An additional requirement is to have the sum of Reseller sales for all the
products that every customer has purchased. If we bring Sum of Reseller
Sales, it won’t work;
the slicing and dicing from the customer table to the FactResellerSales table doesn’t work
This is because the FactResellerSales doesn’t get filtered from the
DimCustomer side. It only gets filtered through the DimProduct, and the
DimProduct is not filtered from the DimCustomer.
the direction of filtering doesn’t support the requirement
One method to solve this is to make the relationship between the
FactInternetSales and the DimProduct both-directional. However, that
method will keep this relationship both-directional always. Another
approach is to keep the relationship single-directional as is. But just for this
requirement, create a measure that uses a both-directional relationship, and
that is when the CrossFilter function comes to help.
You can create a measure as below;
Reseller Sales of the products that this customer purchased =
CALCULATE(
SUM(FactResellerSales[Reseller Sales]),
CROSSFILTER(
DimProduct[ProductKey],
FactInternetSales[ProductKey],
Both)
)

In the expression above, the CrossFilter changes the direction of the


existing relationship between the DimProduct[ProductKey] and
FactInternetSales[ProductKey] to both-directional.

CrossFilter changes the direction of the relationship


The result is working perfectly fine, as you can see in the screenshot above.
Please note that there might be other ways to calculate the same outcome.
However, I used the CrossFilter here to show how this function can be used.

Multiple Relationships
To understand how it works if you have multiple relationships, let’s discuss
another requirement. Let’s say we want to see the Sum of SalesQuote (from
FactSalesQuota) table for all the employees (from DimEmployee) that have
sold products (from FactResellerSales) that each customer has purchased
(from FactInternetSales).
For a requirement as above, we need all tables on the deck. If we use the
sum of the SalesQuota from the FactSalesQuota table, it is not going to
work;

the current relationship doesn’t support the requirement


This time, we have two relationships that are not supporting the direction
needed for the requirement.
two relationships need to be both-directional
The two red relationships above need to be both-directional to get the result.
Our calculation can be like below;
SalesQuota of Employees who have sold the products that this customer purchased =
CALCULATE(
SUM(FactSalesQuota[SalesAmountQuota]),
CROSSFILTER(
DimProduct[ProductKey],
FactInternetSales[ProductKey],
Both),
CROSSFILTER(
DimEmployee[EmployeeKey],
FactResellerSales[EmployeeKey],
Both)
)
As you can see, we can use multiple CrossFilters to change the direction of
multiple relationships.

changing the direction of multiple relationships using DAX in Power BI

Limitations, considerations, and


recommendations
Before you start doing calculations this way, I have to explain a few things:
1. Always consider good modeling to cover the requirement
without the need for a both-directional relationship.
2. If you have to create a both-directional relationship regardless
of the best practice modeling, then use the CrossFilter
approach as much as possible. It can be better for the
performance. The performance impact would be when you use
that particular measure in a report page, not always.
3. The CrossFilter requires an existing relationship between the
two tables.
Summary
In Summary, CrossFilter is a helpful function to change the direction of the
relationship. You can use this method instead of changing the direction of
the relationship itself. However, always consider best practices of the
modeling beforehand. In this chapter, you’ve learned a couple of examples
showing how this function can be used.
Part 5: Logical Functions
Chapter 23: Write Conditional
Statement Using SWITCH in DAX
and Power BI

Conditional expressions are one of the most commonly used expressions in


any language as well as DAX. However, in DAX, if you have multiple IF
THEN expressions, there is an easier way of doing it; using a function that
is called SWITCH. This chapter is about using the switch function in DAX
and Power BI to write a conditional expression.
Multiple IF Statements
If you ever need to write multiple IF statements in DAX, you know that it
makes the expressions hard to read. Here is an example of an expression
with one IF statement:
Back Color = IF(
SELECTEDVALUE(DimCustomer[EnglishEducation])="Bachelors",
"Green",
"White")

The expression above returns Green as the background color if the


EnglishEducation is Bachelors, otherwise, White, here it is used as the
conditional formatting:

Now, if you want to add more IF statements, this becomes getting hard to
read;
This is only for three of those values. You can imagine how the expression
would be if we have five values, or what if we have even more!

SWITCH
The Switch is an efficient function in DAX (and many other languages) to
help writing multiple IF statements much easier. The switch is written in
this way:
SWITCH(
<expression>,
<value 1>,<result 1>,
<value 2>,<result 2>,
...
,<else>
)

If we want to write the expression above using Switch, it will look like this:
Back Color =
SWITCH(
SELECTEDVALUE(DimCustomer[EnglishEducation]),
"Bachelors","Green",
"High School","Red",
"Partial High School","Tan",
"Graduate Degree","Yellow",
"White"
)

You can see that even I’ve added one more condition in the expression
above, and it is still much more straightforward than writing many IF
statements.

Using SWITCH for Not Equal Criteria


(Between, Greater, etc.)
Using Switch for conditions that the value is EQUAL to something is
simple (like what you have seen in the above). However, using SWITCH
when the criteria are NOT EQUAL is a bit tricky. Here is a method that
works:
Back Color =
SWITCH(
TRUE(),
[Sales]>8000000,"Green",
[Sales]>5000000,"Tan",

[Sales]>3000000,"Yellow",
[Sales]<2000000,"Red",
"White"
)

Replacing the expression with TRUE and the value with a conditional
expression means that you get the same output, but this time, you can write
a condition that can be greater than, less than, or even between values.
I hope you use SWITCH in your statements instead of multiple IF
statements much easier with this chapter help. The techniques above,
especially the last one, is what I use a lot in my expressions.
Chapter 24: Stop DAX Cumulative
Total Calculation in Power BI

Suppose you have calculated a cumulative total (such as running total, year
to date, etc.) using quick measures or writing the DAX expression. Then
you realize that the calculation happens even for periods without any data.
You want to stop that calculation at a certain point in time. The trick is
simple. In this chapter, I’ll explain how it works.

Sample Report
I have a sample model to show you how this works, including two tables,
the DimDate and FactInternetSales table.
The DimDate table is marked as a date table, which means I am not using
the default Power BI date table[https://radacad.com/power-bi-date-
dimension-default-or-custom-is-it-confusing].
I have a line chart with FullDateAlternateKey (a date field in the DimDate
table), SalesAmount from the FactInternetSales table in one value, and
Sales YTD, which is a measure in another value.

The calculation for Sales YTD measure is as below;


YTD Sales = CALCULATE(SUM(FactInternetSales[SalesAmount]),
DATESYTD(DimDate[FullDateAlternateKey]))
The problem in the below visual is that no sales are happening after 31st of
July 2008, But still, the Sales YTD shows values until the end of the year.

Sometimes, this might be the desired outcome. Which in those cases, you
don’t need to change anything else. Sometimes your calculation of
cumulative can be a running total, etc.
Also, other scenarios can be showing the calculation results until today (or
tomorrow, or yesterday), but nothing more. You want the calculation to stop
at a certain point in time. Below is a simple trick of how you can do it.

Find the last date with actual values on it


If you intend to stop the calculation whenever the last actual value appears,
then follow this part. For example, let’s say I want the Sales YTD
calculation to happen only up to the last date that I have a sales transaction
(which in this case would be 31st of July 2008). and the Sales YTD after
that should not show anything.
You can find the last date that the actual value happens but calculating the
maximum date value from your actual table. In my case, that would be from
the FactInternetSales table. a simple calculation like below will give me
that;
var _lastActualValue=MAX(FactInternetSales[OrderDateKey])

Because my FactInternetSales table would have data rows only if there is an


actual sales transaction, then the calculation above means that the
_lastActualValue will give me the latest transaction date.

Change the Calculation with an IF


statement
The last part is very simple. All you need to do is use an IF statement and
do the calculation only IF the current date is less than the latest transaction
date. This IF statement can be written in your return clause as below;
IF(
SELECTEDVALUE(DimDate[DateKey])<=_lastActualValue,
CALCULATE(SUM(FactInternetSales[SalesAmount]),
DATESYTD(DimDate[FullDateAlternateKey]))
)

The SelectedValue function is used to get the value from the chart's axis,
and if that particular date is less than or equal to _lastActualValue, it
calculates the expressions. When you don’t define the ELSE part of the IF
statement, it means BLANK in the case of ELSE. And when blank is
returned, the visuals in Power BI (also depends on the visual) won’t show
any value.
So this leads the visual to appears correctly now:

The entire DAX expression for the measure is now as below;


YTD Sales - stop last date =
var _lastActualValue = MAX(FactInternetSales[OrderDateKey])
return
IF(
SELECTEDVALUE(DimDate[DateKey])<=_lastActualValue,
CALCULATE(SUM(FactInternetSales[SalesAmount]),
DATESYTD(DimDate[FullDateAlternateKey]))
)

Stop Based on Today’s date


If you want the calculation to stop at today’s date, you can easily change it
to below;
YTD Sales - stop today =
IF(
SELECTEDVALUE(DimDate[FullDateAlternateKey])<=TODAY(),
CALCULATE(SUM(FactInternetSales[SalesAmount]),
DATESYTD(DimDate[FullDateAlternateKey]))
)

In my sample data this code, won’t be much different than the normal Sales
YTD, because the date of writing this chapter is the 3rd of Sep 2020, and
my sample data is for the years 2005 to 2008. However, it would work
simply in your up-to-date data.

Stop based on other dates related to today


You can easily manipulate the expression above to achieve similar things as
well;
Yesterday:
Today()-1

Tomorrow;
Today()+1

If you are dealing with TODAY() or any functions related to that, remember
the timezone configuration of Power BI servers. I have explained in an
article how that can impact your reports and what you can do about it, read
that article here[https://radacad.com/solving-dax-time-zone-issue-in-power-
bi].

Summary
Changing a calculation to stop at a certain point in time is not complicated.
It is straightforward. You must first find out that point in time (for example,
the latest date for actual value, today, etc.). And then use an IF statement to
check the date in the visual and only shows values until that point in time.
Chapter 25: DAX and Conditional
Formatting Better Together: Find
The Biggest and Smallest Numbers
in the Column

This chapter will show you how to use DAX combined with conditional
formatting to highlight the biggest and smallest number in a column in a
table. In the Power BI world, DAX is your friend, so let’s see how DAX, in
combination with conditional formatting, can do that for you.
Prerequisite
The dataset for this model is the random set of numbers I have created,
which you can download from this book’s code file.
Our sample database table is as below;

Using RANKX to find the biggest and


smallest numbers
RANKX is a function that can be used in many scenarios when you are
calculating the rank of a value based on a category. Imagine that we have a
table visual like the below example:
Our first step is to create a measure to give us the rank of values based on
customers. And using RANKX, we can write a measure like below;
Rank of Revenue = RANKX(
ALL('By Customer'),
CALCULATE(
SUM('By Customer'[Revenue])
)
)

“By Customer” is our table name, and Revenue is the column that we want
to find out its ranking.
Now you can add that measure in the table visual, and you will see this
output
Using Switch to Choose Color
Now that we know the biggest number and the smallest number (using the
result of the RANKX expression), we can set the color based on it. The
SWITCH is a function that works like multiple IF THEN ELSE statements.
We can write another measure as below;
Background Color = SWITCH(
[Rank of Revenue],
1,"Green",
25,"Red",
"White"
)

Let’s translate the code above to if-then-else; if the revenue rank is 1, the
color is green. If it is 25, the color is red, and otherwise, for any other
values, it is white. This is the measure that we will be used for coloring the
values in the table.

Set Conditional Formatting for


Background Color
Now that we have everything ready, we can do the conditional formatting
on the table. Select the table visual first, then go to the Format tab, and
under conditional formatting, select Revenue as the column.
Set the Background color to On, and you will see conditional colors appears
immediately. However, this is not the coloring we want. So click on
Advanced Controls.
In the advanced control, set the Format By to Field Value and then select
the Background Color measure we created in the previous step. Then click
on OK.
Note that if you are creating your measures; The measure that you use here
should be producing color values as the output.
After clicking on OK, you will see that there will be only two values color-
coded, the biggest one as Green and the smallest one as Red.
You got the very first and the very last number in the ranking now color-
coded. How simple it is when DAX and Conditional Formatting works with
each other! Now, let’s talk about some enhancements.

Font Color: A bit more enhancement


As you can see in the above screenshot, the text value of the revenue is not
that readable because the colors are rather dark. Best would also be creating
another measure for Font Color as below;
Font Color = SWITCH(
[Rank of Revenue],
1,"White",
25,"White",
"Black"
)

Adding that to the table, you can see how it works:

Now, let’s do the conditional formatting this time for Font Color;
In the advanced controls window; Choose the Fixed Value, and then Font
Color;

Here is now the final output:


More Enhancements: Color Coding top 3
and bottom 3 values
Well, before you ask for this, I thought it better to show you straight away!
How if we want to color code the top and bottom 1 number and the
top/bottom three numbers? Well, that is easily possible. You need to change
your measure expression for the background and font color as below;
Background Color Three = SWITCH(
[Rank of Revenue],
1,"Green",
2,"Green",
3,"Green",
23,"Red",
24,"Red",

25,"Red",
"White"
)

It is not a good way of writing what we are after. You need to use Switch,
but use it for multiple values. Here is a better way of doing it:
Background Color Three = SWITCH(
TRUE(),
[Rank of Revenue]<=3,"Green",
[Rank of Revenue]>=22,"Red",
"White"
)

same for the Font Color;


Font Color Three = SWITCH(
TRUE(),
[Rank of Revenue]<=3,"White",
[Rank of Revenue]>=22,"White",
"Black"
)

and then if we use these two new measures (Background Color Three and
Font Color Three) for conditional formatting, this is what we get;
What If Parameters for Conditional
Formatting: The sky is the limit!
When it comes to combining DAX and visualization, the sky limits what
you can do. Let’s say you don’t know is it the top three that you want to
color code, or four, or five. And also, you don’t know it is different from the
bottom bound of the values. So, as a solution, you can use What If
parameters in Power BI to create two parameters; one for the upper bound
and one for the lower bound.
Start by creating a new what-if parameter under the modeling tab. Name it
as Upper Bound, and then set the minimum as 1, the maximum as 10, the
default as 5, and the increment 1. Make sure the Add slicer to this page is
selected.

Do it one more time for the lower bound with the configuration below;
Now you should have two slicers on your page for each of the what-if
parameters.

Let’s use these two in our background color and font color measures. This
is what the updated background color measure looks like:
Background Color Parameter = SWITCH(

TRUE(),
[Rank of Revenue]<='Upper Bound'[Upper Bound Value],"Green",
[Rank of Revenue]>=
CALCULATE(
COUNT('By Customer'[Customer]),
ALL('By Customer')
)+1-'Lower Bound'[Lower Bound Value],"Red",
"White"

Well, the DAX expression is a bit more complicated than what you
expected! Let’s explain a bit of detail here: ‘Upper Bound'[Upper Bound
Value] and ‘Lower Bound'[Lower Bound Value] are the values selected in
the slicers of what-if parameter tables. Because the Lower Bound value is a
value between 1 to 10, we want this value to be deducted from the
maximum rank in the revenue column, so I used a calculate function to
count all records in the table and then use that as the source of deduction. I
added one to it to avoid results such as 25-1=24. We also want 25 to be
color-coded, which is 25+1-1.
And for the Font color;
Font Color Parameter = SWITCH(
TRUE(),
[Rank of Revenue]<='Upper Bound'[Upper Bound Value],"White",
[Rank of Revenue]>=
CALCULATE(
COUNT('By Customer'[Customer]),
ALL('By Customer')

)+1-'Lower Bound'[Lower Bound Value],"White",


"Black"
)

After conditional formatting, this is the result:


It works even for other visuals
The solution you learned in this chapter is not just for table visuals. You can
use it in a bar chart, column chart, and some other visuals. Obviously, for
these, because the background color white would be a bit invisible, I
changed the measure as below;
Background Color Parameter Chart = SWITCH(
TRUE(),
[Rank of Revenue]<='Upper Bound'[Upper Bound Value],"Green",
[Rank of Revenue]>=
CALCULATE(
COUNT('By Customer'[Customer]),
ALL('By Customer')
)+1-'Lower Bound'[Lower Bound Value],"Red",
"Orange"

)
The above measure replaced the White color with Orange.
And here is the output now:

Summary
In this chapter, multiple techniques were used to achieve something I
believe every business would need in their visualization; conditional
formatting based on top/bottom values. We used the RANKX function in
DAX to calculate the rank of values, and then using SWITCH, we produced
the output of coloring. Then using conditional formatting with the fixed
value, we put it in the visualization. You also learned how the process could

be enhanced using parameters as a more dynamic approach.


Part 6: Time Intelligence
Chapter 26: Power BI Date
Dimension; Default or Custom? Is
It Confusing?

If you have worked with Power BI for some time, you know two types of
Date dimensions; Custom or built-in/Default. It is always confusing for
people, which date dimension is suitable to use, and what is the difference
between these two approaches. Also, based on selecting the type of Date
dimension, your DAX calculations may differ slightly. This chapter will
explain all you need to know about the default and custom date dimensions
in Power BI and help you choose the right one for your Power BI solution.

Power BI Default Date Dimension


The Power BI Date dimension is still a bit of a mystery for some users.
Many users still are not aware that there is a default or built-in date
dimension. This date dimension hasn’t existed since the beginning of the
Power BI Desktop (July 2018). It came a bit after the party. The purpose of
this default date dimension is to ease the way that time intelligence
calculations work in Power BI and make the whole experience easier for the
user. Let’s see how this dimension works.
Power BI Creates a Default Date Dimension for
every single date field in your dataset
By default (you can change the default configuration), Power BI creates a
date dimension for every single date field in your dataset. The date
dimension is a generic date dimension with standard fields such as; Year,
Month, Quarter, Day, etc. The configuration in Power BI Desktop that
allows the model to create the default date dimension is here:
In the Power BI Desktop, File menu -> Option and Settings -> Options
In the Options window, under Current File, Data Load; Time Intelligence:
Auto Date/Time
Enabling this item means that Power BI automatically creates a hidden date
table for each field in the model with a date or date/time data type. The
reason that it is not easy to find the default Date table is that it is HIDDEN!
The main reason for having this table hidden is that the user will face too
much confusion if you see a Date table per Date data type column. Here is a
model created with the default Date dimension:
In the screenshot above, you see three date fields in the FactInternetSales:
DueDate, OrderDate, and ShipDate. There is a date dimension TABLE for
each of these fields that you cannot see here. But if you have an option in
the Power BI settings enabled, you can see the Date hierarchy under that
table, which shows a table behind the scene. (Note that even if you don’t
see the date hierarchy in this view, it doesn’t mean that Power BI default
date dimension is not created). If you want to enable the feature to SHOW
you the Date hierarchy, you can do it under Options, Preview Features. and
enable “Show dates as a hierarchy in the fields list.”

Why a Date table for every single Date Field?


Well, now that you know there is a default Date dimension, your second
question might be: Why Power BI creates it multiple times for each date
field?! The reason is that the Date usually acts like a role-playing
dimension. Sometimes it might be Due Date, sometimes Ship Date, and
sometimes, Order Date. All of these options are date fields, but their values
and behavior are different. If you read the earlier chapter in this book about
calculated tables, you know that one of the ways to do the role-playing
dimension in Power BI is to create copies of the Date dimension. This is
what Power BI does behind the scene automatically. Power BI Creates a
template for the Date table first and then copies it for every single date or
date/time field in the model. Here is a glance at the behind scene of the
Power BI model:

Note that you cannot see the view above in the Power BI Desktop. You can
use tools like Power BI Helper[https://radacad.com/power-bi-helper] to get
to that information, though. In the screenshot above, you can see a
DateTableTemplate, and then three Date tables copied from that template.
What does the Default Date table look like?
There are many variations of the Date dimension, and you may think, what
does the default Date table look like? What columns are available there, and
what columns are not? Here is the list of columns:
The view above can be generated with tools such as Power BI Helper. But if
you are interested to see the list of these column names in the Power BI
Desktop, One way is to see it when you write a DAX expression. After
typing a dot (.) after the Date or Date/Time field name, you get the list of
fields;

This might have been a mystery for many people when they write the DAX
statement. “What is the list of fields that comes after the dot (.) in front of a
date field name?” Now you know the answer;
The Date field is NOT a column from the Power BI model
point of view. It is a TABLE, a hidden table, and because of
that, you can choose which column in that table you want
to use within your expression.

Writing Time Intelligence Calculations with the


Default Date Dimension
Writing DAX expressions for the time intelligence calculations using the
default date dimension is simpler. You just need to use your Date field name
plus a “.[Date]” at the end. This means that you are using the [Date] field of
the hidden Date table for the expression. For example, here is how a year to
date calculation looks like:
Sales YTD = TOTALYTD(
SUM(FactInternetSales[SalesAmount]),
FactInternetSales[OrderDate].[Date])

If you don’t use the “.[Date]” then you won’t get the correct result because
Time Intelligence calculations need a DATE column to work with, and with
the “.[Date]”, you choose the date column in the default hidden Date table.
As you can see, the calculation doesn’t work if you do not include the “.
[Date]” in the expression. But if you include it, then all is good to do.
Writing time intelligence expressions using the default Date Dimension is
very easy, as you’ve seen here.
Default Date Dimension has a Built-in Date
Hierarchy
One of the main benefits of using the default Date dimension is the built-in
Date hierarchy of Year/Quarter/Month/Day it provides. Whenever you drag
a Date field, Power BI automatically shows the hierarchy under visual
because there is a hidden Date field with the built-in hierarchy behind the
scene.

Default Date Dimension Consumes Memory


Oh yes! Of course, like any other table structure in the Power BI in-
memory-based structure, every date table consumes memory. But it would
do the same even if you create your custom date dimension! Whenever you
do the role-playing dimension scenario, you are also consuming even more
memory! The main difference is that the Power BI default Date dimension
will be created even if you do not want to do the date-based analysis on a
date field! For example, even if you don’t use DueDate in your date-based
analysis, Power BI still creates a date dimension for it. You cannot stop it
for one field. You have to either disable the default creation of the Date
dimension for the entire model or use it for the whole model. You cannot
customize it per field. But with the custom date dimension, you can.

Custom Date Dimension


If the default Date dimension is available, why should I have a custom date
dimension? Well, there are some reasons for doing that. Let’s first check
how you can use a custom date dimension.
Mark as Date Table
To use your custom Date dimension, you have to mark your table as a Date
table. This is an essential step for Power BI because it will know that the
table is to be used for time intelligence calculations. You can, of course,
have more than one Date table to be marked as the Date table (Because of
the same reason of role-playing dimensions). If you have your custom Date
table, here is how to mark it as a Date table; Go to the Modelling tab in the
Power BI Desktop, Then choose the custom Date table of yours, and select
Mark as Date Table.
You have to select a full-date column as the Date column of the Date Table
as well.

Usually, after this change, if you look at the icon of Date fields under your
custom Date table, you will see them differently (without the default Date
hierarchy), which shows the table now successfully marked as a Date table.
Writing Time Intelligence Calculations with
Custom Date Dimension
The prerequisite for this step is to mark the table as Date Table, which we
have done in the previous step, now you can write a DAX expression as
easy as below:
Sales YTD = TOTALYTD(
SUM(FactInternetSales[SalesAmount]),
DimDate[FullDateAlternateKey])
As you can see, in this expression, we do not need “.[Date]” to get to the
date field. Because there is no hidden Date table for this column, you just
refer to the column to get the Date field. If you use the “.[Date]” here, you
get an error because there is no hidden Date table here.

Default or Custom Date Dimension?


Now that you know all about the default Date dimension and custom Date
dimension, is time for the main question: What is the difference?! when to
choose what? The answer, like many other situations, is Depends! If you
want to use generic date-based analysis and build a model easier and
quicker, then the default Date dimension is beneficial in those scenarios.
But if you're going to do a unique date-based analysis (as an example;
public holiday-based analysis), then the custom Date dimension will give
you more power. Let’s look at differences in detail:
Modeling with the default Date Dimension is
Much Easier
Using a custom Date table means taking care of relationships, marking as a
date table, creating the default hierarchy, etc. If you use the custom Date
dimension, you have to spend more time doing all these configurations,
whereas the default Date table will take care of you.
If you have a Date field, and you are not using it,
Remove It!
When you have a date field, Power BI automatically creates a table for it,
establishes the relationship of that to the primary Date field, and the table
consumes memory! If you do not intend to use that field, then remove it to
save memory. This is also important for any other fields that you do not use
in the model; remove it to get better memory consumption, but it is even
more critical for Date fields because, behind the scene, you will have not
just a field but also a table.
Customized and Complex Analysis is Easier with
Custom Date Dimension
While the default Date dimension is easier for generic date-based analysis,
The custom Date dimension is a potent option for customized analysis. As
an example, let’s say you want to create a date-based analysis based on
public holidays. How can you do that with the default Date dimension? The
answer is to create a list of public holidays as a table and merge or join it to
the date field, which means making your custom Date dimension. Here in
this post[https://radacad.com/create-a-date-dimension-in-power-bi-in-4-
steps-step-3-public-holidays], I explained an example of fetching public
holidays for a custom Date dimension in Power BI.
Another example is when you need more than the default hierarchy to
create a weekly hierarchy, financial calendar hierarchy, and many other
scenarios. The default Date dimension is suitable for generic analysis, but
not when it comes to more customization.
Common Mistake to Avoid!
One big common mistake that I’ve seen a lot, and it comes from the
confusion of the default Date dimension vs. custom Date table, is that we
see both in one model! let’s see what I mean:
Let’s say you want to use a custom Date dimension, and you add it to your
model, you create the relationship to the date field in the fact table, and then
you DO NOT Mark it as a Date Table! That is where all mistakes
start! When you do not mark it as Date Table, you allow Power BI to create
the default date dimension for the date field even under this table
(considering that the creation of default date tables is enabled in the options,
which is ON by default). As a result, you have a custom Date table, but you
also have a default Date dimension for the date field under your custom
date table! It means you are using extra memory twice! And your DAX
expressions also becomes even more wrong like this:
Sales YTD = TOTALYTD(
SUM(FactInternetSales[SalesAmount]),
DimDate[FullDateAlternateKey].[Date])

This is Wrong! You will get the correct result in the visualization, but doing
it this way is Wrong! Because if you are going to use the default Date table,
then what is the point of adding an extra custom Date dimension? If you are
going to use the custom Date table, you HAVE TO mark it as a Date Table.

Summary
Date dimension and its behavior in Power BI can be confusing if you don’t
know about the default Date dimension and how to use your custom Date
dimension. In this chapter, I explained the differences between these two
and elaborated on the difference.
Chapter 27: Creating Calendar
Table in Power BI using DAX
Functions

A couple of DAX functions make the process of creating a calendar table


straightforward; Calendar() and CalendarAuto(). In this short chapter, I’ll
explain what these functions are and how you can use them to create a
calendar table in just a few seconds.
Prerequisite
The dataset for this model is the AdventureWorksDW2012 Excel file,
which you can download from this book’s code file. The tables used in this
example are; DimCustomer and FactInternetSales.

Calendar() Function in DAX


One of the easiest ways of creating a calendar table is using the Calendar()
function in DAX. The Calendar function is a very simple function with just
two input parameters; start date and end date.
<table output>=Calendar(<start date>, <end date>)

The output of the Calendar function is a table with one column which
includes all dates between the start and end date, with one day at each row.
Here is an example of creating a calendar table using this function:
Create a new Table. (The output of the Calendar function is a table)

Then write the expression below;


Calendar = CALENDAR(DATE(2018,1,1),DATE(2019,12,31))

The two inputs here are two date fields, so I used Date functions to generate
them from the year, month, and date. You can always use Date() functions
in this way:
Date(year, month, day)

The output of this calculation is a table with one column and values starting
from 1st of Jan 2018 and end on 31st of Dec 2019. This is how easy it is to
use the Date table;
It is not mandatory to put static dates when you define the calendar table.
You can even use it with dates relative to the current date. Here is another
example of creating a calendar table; with the range of dates from a year
before today to a year after;
Calendar Relative = CALENDAR(
TODAY()-365,
TODAY()+365
)
Or you can even create it based on a column, and start with the minimum
date in that column and end with the maximum date, like the below
expression;

But wait! instead of doing it this way, there is a better function for it;
CalendarAuto()

CalendarAuto() DAX Function


CalendarAuto() function also produces a table with a column of dates, one
day at a time. However, you don’t set the start and end times. The start and
end time would be based on the minimum date value in your data model
(Across all columns, except calculated columns, tables, and measure) and
maximum date value in your data model (Across all columns, except
calculated columns, tables, and measures). This is how you use the
CalendarAuto function;
<table output>= CalendarAuto([<fiscal year’s start month number>])

The fiscal year’s start month is an optional parameter. If you don’t set it, it
will use the calendar year instead and starts in January and ends in
December. Here is an example of using it:
CalendarAuto = CALENDARAUTO()

As you can see, the date values are starting from the 1st of January 1910.
The reason is that somewhere in our data model, there is a date field, which
has a value in 1910. It might not be the first of January of that year,
however, but because the CalendarAuto function always starts on the first
day of the year (or fiscal year) and ends on the last day of the year (or fiscal
year), it started then from 1st of January.
Now If I want to do it as a fiscal calendar considering that the 1st of July is
the first day of a fiscal year, this is how I can use it: (Note that you should
enter the last month of the fiscal year, in this example: 6, saying June is the
last month)

Is it better to use Calendar or


CalendarAuto functions in DAX or build
the date dimension using Power Query?
This is always the question that I get; where should I build my date
dimension? My answer is always one thing: Wherever you feel more
comfortable with it! You have to maintain this dimension table in the future,
so you have to decide where to build it. There are pros and cons of building
it everywhere, for example;
Calendar() and CalendarAuto() functions are straightforward
to use and fast to create a Date table.
If you create a [https://radacad.com/create-a-date-dimension-
in-power-bi-in-4-steps-step-1-calendar-columns]Date table
using Power Query, then you can query live APIs and web
services and fetch public holidays[https://radacad.com/create-
a-date-dimension-in-power-bi-in-4-steps-step-1-calendar-
columns] and other information live.
If you build your Date table in the data
source[https://radacad.com/script-to-generate-and-populate-
date-dimension-version-2-adding-multiple-financial-years],
such as the SQL Server database, you can then use it across
multiple visualization tools.

Summary
Calendar and CalendarAuto functions are helpful and very simple-to-use
functions in DAX. You can create a date/calendar table with one of these
functions in just a few seconds.
Chapter 28: All in One: Script to
Create Calendar Table or Date
Dimension using DAX in Power BI

I have written an article with the full script of generating a date dimension
in Power BI using the Power Query script, and I would always recommend
that as the first choice. However, sometimes, you want this to be in DAX
way, so I explained how to create a fully-fledged date table using a DAX
script in this chapter.

Introduction and background


information: Date Dimension
Date Dimension or Calendar table is a table with one date at every row and
the columns representing that date's attributes (such as year, month, quarter,
etc.).

Columns Included in the Date Dimension


This date dimension (or you might call it a calendar table) includes all the
columns related to the calendar year and financial year as below;
How to use the Script?
Create a new table (calculated table) in Power BI:

create a calculated table in Power BI


Then just copy and paste the script provided in this chapter there and press
ENTER.

paste the DAX script to create a date dimension in Power BI


Mark the table as a Date table, by right click on the table,
Mark as a Date table
In the Mark as date table’s setting, select the Date column in the dropdown,
and click on OK.

Mark as date table’s setting in Power BI


Now your date dimension is ready. You can connect it to other tables using
relationships and start slicing and dicing the data with the fields in the Date
table.

Script
Download the script for the date dimension from this book’s code file.

Configuration
You need to configure the Date table based on your need. The first few lines
are the configurations that you can set based on your requirement;

set the start and end year, and the starting month of the fiscal year

Considerations
There are a few things you need to consider if you are using this script;
This Date dimension does NOT include public holidays
information. If you wish to get that, use this
approach[https://radacad.com/create-a-date-dimension-in-
power-bi-in-4-steps-step-3-public-holidays].
This Date dimension is not supporting scenarios with fiscal
weeks. For those scenarios, some changes need to be applied
to the script.
If you want to use this date dimension in multiple Power BI
files, consider using the Power Query version
[https://radacad.com/all-in-one-script-to-create-date-
dimension-in-power-bi-using-power-query]and a dataflow
entity for the date dimension.
Chapter 29: Day of Year and Day
of Quarter – DAX calculations for
Power BI

Power BI has some built-in, easy-to-use DAX functions to get the Day of
Month and Day of the week, but nothing for Day of Year and Day of the
quarter. These calculations, however, are straightforward to implement
using other functions. In this short chapter, I explain a method to calculate
those for Power BI.

Day of Year
A straightforward way of calculating Day of Year is to get the date
difference of that date with the starting day of that year. Here is how it
works:
Day of Year = DATEDIFF(STARTOFYEAR('Date'[Date]),'Date'[Date],DAY)+1
This code will give us the day number of the year for a given date.
‘Date'[Date] means the column named “Date” under the table named
“Date”.

DAX expression to calculate the day of the year in Power BI

Day of Quarter
You can use the same method and get the date difference of the given date
with the starting date of that quarter.
Day of Quarter = DATEDIFF(STARTOFQUARTER('Date'[Date]),'Date'[Date],DAY)+1

DAX expression to calculate the day of the quarter in Power BI

Days until the end of the quarter


If you compare with the end of the quarter, you get the number of days
remaining from the quarter.
Days until the end of the quarter =
DATEDIFF('Date'[Date],ENDOFQUARTER('Date'[Date]),DAY)

calculate the number of days until the end of the quarter using DAX

Days until the end of the year


The calculation for counting the number of days until the end of the year is
as below;
Days until the end of the year =
DATEDIFF('Date'[Date],ENDOFYEAR('Date'[Date]),DAY)
count the number of days until the end of the year using DAX in Power BI

Day of Month and Day of Week


For the day of the Month and Day of the week, you don’t need a custom
expression, the DAY function will give you the day of the month, and
WeekDay will provide you with the day of the week (with the ability to set
the start date of the week).

Day of month and day of the week using DAX


Power Query Functions
These calculations can also be done in Power Query. If you are using the
calculation in a dynamic DAX measure, then the calculations above would
help. But if you need them to be added as a column or a pre-calculated
expression, then I suggest doing it in Power Query.
Chapter 30: Get the Day of the
Week Name and Number in Power
BI Using DAX

If you don’t have a date table with a column that represents the day of the
week name (Saturday, Sunday, Monday, etc.) or number (from zero to six,
or from one to seven), and you have a date field, which you want to get the
day name of the week quickly, here is a quick trick for you.

Sample Table
The below DAX calculated table is a table with a list of dates in it;
calendar = CALENDAR(
DATE(2020,1,1)
,TODAY()
)

Day of Week Name


If you want to get the Day of Week Name from this date, Monday, Tuesday,
Wednesday, etc. You can use the FORMAT function as below:
Day of Week Name = FORMAT('calendar'[Date],"dddd")

Get the Day of Week Name in DAX

Three Characters
If you just want the three-character day of week name, you can use “ddd” in
the format function as below;
3 characters =
FORMAT(
'calendar'[Date],
"ddd"
)

Many other format strings are helpful to get other date or time attributes.
You can find them all here[https://docs.microsoft.com/en-us/dax/custom-
date-and-time-formats-for-the-format-function].

Day Number of Week


If you just want a number representing the day number of the week, then
you can use the WeekDay function;
WeekDay = WEEKDAY('calendar'[Date])
The default setting is that the weekday starts on Sunday being 1, and then
Saturday is 7. You can change it with the 2nd parameter of the Weekday
function as below:
Return type: 1, the week begins on Sunday (1) and ends on
Saturday (7). numbered 1 through 7.
Return type: 2, the week begins on Monday (1) and ends on
Sunday (7).
Return type: 3, the week begins on Monday (0) and ends on
Sunday (6).numbered 1 through 7.
Reference: https://docs.microsoft.com/en-us/dax/weekday-function-
dax[https://docs.microsoft.com/en-us/dax/weekday-function-dax]
weekday starting Monday 1 = WEEKDAY('calendar'[Date],2)
Chapter 31: Some Methods for
Calculating Quarter in DAX for
Power BI

Recently the Quarter function is added to DAX in Power BI. However, it


wasn’t there until late 2020. Understand how the quarter is calculated can
help you to learn some DAX functions in Power BI. Here in this short
chapter, I explain some easy methods for calculating quarters.
Sample Data
To start this example, you can open a new Power BI file, create a new
calculated table, with the below expression that gives you a date table with
one column:
Date = CALENDAR(
DATE(2019,1,1),
DATE(2020,1,1)
)

Using the Format Function


One easy way to calculate the quarter from a date field is the Format
function with a format string of “q”. this will give you the Quarter number
as a text format.
FORMAT('Date'[Date],"q")

the output is:

You can then use a function such as INT if you want to achieve the number:
INT(FORMAT('Date'[Date],"q"))

the output is:


Or, if you want to build a text value for it, such as QTR 1, you can do this:
FORMAT('Date'[Date],"\QTR q")

The \ in the format string above is an escape character, which means this Q
after the \ will be an actual Q letter rather than the q that the quarter number
will replace.
the output is:

Calculating it from Month


Another way to calculate the quarter is to derive it from the month
calculation. Mainly a divide by three and the round it. Here are some
options:
Ceiling
You can use the Ceiling function to get the round-up number of the divide
by three from the month value as below;
CEILING( MONTH('Date'[Date])/3 ,1)

the output is:

RoundUp
In this scenario, you can also use the roundup function to achieve the same
thing with the same approach:
ROUNDUP( MONTH('Date'[Date])/3 ,0)

the output is the same:


Round
It is not my preference in this scenario to use Round, but if you want just to
see another method to calculate it, here it is:
ROUND(
(MONTH('Date'[Date])+1)/3
,0)

You need one extra step because the round might end up with zero for some
values. You first have to add one to the month value and then do the divide
and rounding. The output is the same.

Other Quarter Related Functions


Other functions can help work with Quarters, such as StartOfQuarter
STARTOFQUARTER('Date'[Date])

and EndOfQuarter:
ENDOFQUARTER('Date'[Date])

Here is the output:


There are also two other functions: PreviousQuarter and NextQuarter.
However, these two functions don’t return one value. They produce a range
of dates, which can help filter other functions.
Chapter 32: Basics of Time
Intelligence in DAX for Power BI;
Year to Date, Quarter to Date,
Month to Date

In this chapter, first, I explain what time intelligence is and the requirements
for setting up time intelligence calculations. I will talk about DAX
functions and expressions that help get insights such as year to date, year
over year comparison, etc.
Prerequisite
To run examples of this chapter, you would need to have the
AdventureWorksDW excel file dataset. The table we are using is only one
table: FactInternetSales to be loaded into Power BI.

What is Time Intelligence?


Time Intelligence functions in DAX are functions that give you insight
from the date and time dimensions. Most of the analysis by date and time
are in that category, such as year to date, quarter to date, month to date,
same period last year calculations, etc. These calculations all have one
dimension in common; date/time dimension.

Before Using DAX Functions


Before using any of the DAX functions that give you time intelligence
output, you must know that there is a requirement for all these functions to
work. If you want to work with these functions, you HAVE TO have a date
dimension (some people call it a calendar or time dimension, although the
time dimension is different) in your data model. This date dimension should
have some requirements;
The date dimension that is acceptable by time intelligence functions of
DAX should;
have one record per day
Has the range of dates you need from minimum available to
the maximum available dates.
have no date missing (if there are no sales in the 1st of
January, still that date should be in this table. This is one of the
reasons why you do need to have a separate date table)
Where to Get the Date Dimension?
There is a chapter earlier in this book with a full script of the Date
dimension.

Year to Date; TotalYTD


Let’s start the example with a simple function to calculate year to date. The
Year to date calculation is an aggregation of values from the beginning of
the year to the specified date. For example, the year-to-date sales value can
summarize all sales from the 1st of January of that year to the selected date.
There is a function in DAX specifically for the year-to-date calculation,
named TotalYTD[https://docs.microsoft.com/en-us/dax/totalytd-
function-dax]. Here is the signature of the TotalYTD function;
TotalYTD( <expression>, <dates>, [<filter>], [<year end date>])

The first two parameters are mandatory;


Expression: The expression that applies aggregation of a value
dates: The date field of the date dimension.
In our example, we are calculating the sum of the SalesAmount field in the
FactInternetSales. So the expression would be:
Sum(FactInternetSales[SalesAmount]).
Because we are using the default Date dimension, when you type the date
field name, you will have the option to select a field from that table to
select the “.[Date]” field. This means the date field in the default date table.
So, as a result, here is the expression to calculate year to date: (Note that
this is a measure, not a column)
Sales YTD = TOTALYTD(
SUM(FactInternetSales[SalesAmount]),
FactInternetSales[OrderDate].[Date]
)

and the sample output is:


As you can see, the Sales YTD measure is accumulated values of all dates
before it from the start of the year (to get the correct output, you have to
have OrderDate in your visual, and it should be ordered by OrderDate
ascending). The visual above shows calculation by every day. Remove the
day from the visual (you can remove it from the Fields section of the
visual),

then you can get the year to date calculation at the monthly level as below;
The year-to-date calculation (for every month) is the accumulated sales of
all months before that (from January of that year).

Year to Date Another Approach:


DatesYTD
TotalYTD is one of the methods of calculating the year-to-date value. There
is another way that can be helpful in more complex DAX expressions when
you want to combine multiple filter criteria. That way is using a function
called DatesYTD [https://docs.microsoft.com/en-us/dax/totalytd-function-
dax]combined with Calculate function. DatesYTD is a function that accepts
only two parameters, which one of them is optional;
DatesYTD(<dates>, <year end date>)

DatesYTD returns a table as the output, a table with all dates in a year to
date. That is why we need to use a function such as Calculate.
Here is how the calculation works with DatesYTD function;
Sales YTD Method 2 = CALCULATE(

SUM(FactInternetSales[SalesAmount]),
DATESYTD(
FactInternetSales[OrderDate].[Date]
)
)
You may ask which one is a preferred option? TotalYTD or DatesYTD. The
answer depends on the type of filter you are using. If you are using multiple
filter criteria, I would suggest DatesYTD because you can apply whatever
filter you want inside a Calculate. You may be able to do that still with
TotalYTD, but you probably make the expression a bit complicated.

Fiscal or Financial Year to Date


Calculating the calendar year to date was easy; how about the fiscal or
financial calculation? Do we have a function for those? No. However, there
is a parameter that you can add to the expression, and that makes the
calculation fiscal. The <year end date> parameter is an optional parameter
that we have not used in the previous example. When you do not assign a
value for this parameter, the default value would be considered 31st of
December of each year. If you want to specify a value for this parameter,
this is an example of how you can do that:
Sales YTD Fiscal = TOTALYTD(
SUM(FactInternetSales[SalesAmount]),
FactInternetSales[OrderDate].[Date],
"06/30"
)

As you can see from the structure, the year-end date is set as month/day.
You can use a few other options, such as 06-30, 6/30, June 30, or 30 June.
“06/30” value as the parameter here means that the end of the fiscal year is
30th of June of each year, and start as the result would be 1st of July of the
year. Here is the output; as you can see, the calculation restarts in July each
year instead of the calendar year, starting from January.

The approach is very similar if you want to use the DatesYTD approach.
Here is the code:
Sales YTD Fiscal Method 2 = CALCULATE(
SUM(FactInternetSales[SalesAmount]),
DATESYTD(
FactInternetSales[OrderDate].[Date],
"06/30"
)
)

Quarter to Date Calculation: TotalQTD


When you know how the calculation of the year to date works, you can
guess how it would work for the quarter to date as well. The only difference
is the function for the quarter to date is called TotalQTD. It can be used
precisely similar to the way that we used TotalYTD in the previous
example;
Sales QTD = TOTALQTD(
SUM(FactInternetSales[SalesAmount]),
FactInternetSales[OrderDate].[Date]
)
As you can see, this calculation accumulates sales values up to the end of
each quarter.

Quarter to Date Calculation: DatesQTD


Similar to the DatesYTD, there is also a function for DatesQTD, which can
be used the same way. Here is the code for it:
Sales QTD Method 2 = CALCULATE(
SUM(FactInternetSales[SalesAmount]),
DATESQTD(
FactInternetSales[OrderDate].[Date]

)
)
Month to Date Calculation: TotalMTD
You can use the TotalMTD function very similar to the other functions you
have seen in previous examples to calculate the month to date. Here is the
code:
Sales MTD = TOTALMTD(
SUM(FactInternetSales[SalesAmount]),
FactInternetSales[OrderDate].[Date]
)

And the output (note that you can test it better when you have DAY on your
visual to see the accumulation happening);
Month to Date Calculation: DatesMTD
The same approach can be applied for the DatesMTD as below;
Sales MTD Method 2 = CALCULATE(
SUM(FactInternetSales[SalesAmount]),
DATESMTD(
FactInternetSales[OrderDate].[Date]
)
)
More Functions?
As you have seen in this chapter, using Time intelligence functions is not
hard to start. In the following chapters, I’ll explain a few other time
intelligence functions.
Chapter 33: Month over Month
Calculation in Power BI using DAX

When working with dates, one of the common types of analysis is period
vs. period, such as Year over year and month over month. This chapter will
explain how you can use DAX to write calculations for month-over-month
simply in any Power BI report.

What is a month-over-month calculation?


Month-over-month means comparing the value of each month with the
value of the month before. An example is below;
Month over month calculation
This calculation can be done using many different ways in Power BI, most
of them using DAX. You can use various functions to achieve the result. I
am just showing one of the ways using the ParallelPeriod function.

ParallelPeriod function in DAX


ParallelPeriod is a tabular function that returns a parallel period table to the
current period. You can select what the period should be (internal) and the
number of it back or forth. Here is how the function can be used;
PARALLELPERIOD(<dates>,<number_of_intervals>,<interval>)

Here are how parameters work;


dates: the Date column that slices and dices the visual
number_of_intervals: How many periods you want to go back
(negative number) or forward (positive number)
interval: the period
This function returns a table of dates and cannot be used directly in a
measure. You can wrap it in other functions to return a scalar value for a
measure.
The date field is the most important parameter here. This should be the date
field from the date table, which can be the date field in either a custom date
table or the default date table of Power BI. Let’s look at them one by one.
Default date table sample of Sales last
month
If you have a date field in your table, and you have not turned off the auto-
date/time in Power BI, that most probably means you have a built-in default
date table created by Power BI, which you can use the field from it to
calculate the sales last month like below;
Reseller Sales last month =
CALCULATE(
[Reseller Sales],
PARALLELPERIOD(
FactResellerSales[OrderDate].[Date],
-1,
MONTH)
)

The [OrderDate].[Date] is representative of the date field in the default date


table. The .[Date] part of this is important because otherwise, you are not
using the date field of that table. Here are the results of the expression
above:
Sales last month calculation in Power BI
The interval is Month, which means we are getting the sales of a month.
That month is the previous month because the number of intervals is -1.
The date field should be the same field used as the Axis of the visual.

Custom date table sample of Sales


previous month
If you are using a custom date table, you have to mark it as a date table in
Power BI, and then you can use the date field directly in the ParallelPeriod
without the “.[Date]” part.
Internet Sales last Month =
CALCULATE(
[Internet Sales],
PARALLELPERIOD(
DimDate[FullDateAlternateKey],
-1,
MONTH)
)

The expression above can return the same result for the previous month’s
calculation:

Sales last month calculation in Power BI using a custom date table

Month over Month variance


Once you got the calculation of the previous month, the month-over-month
variance is just a subtract.
Internet Sales MoM Var = [Internet Sales]-[Internet Sales last Month]
Month over Month percentage (growth or
shrinking)
And the percentage would be another simple calculation like below:
Internet Sales MoM % = DIVIDE([Internet Sales MoM Var],[Internet Sales last Month])

Here are the results with some conditional formatting added;

Month over month variance and percentage in Power BI

Other intervals and periods are possible


ParallelPeriod gives you the option to change the interval to Quarter or Year
too, and you can change the number of intervals to more and change it to
negative and positive. Other functions can be used for this type of
calculation. The DateAdd is one of them.
Chapter 34: DatesInPeriod vs.
DatesBetween; DAX Time
Intelligence for Power BI

Two functions work very similarly but have a bit different usage;
DatesInPeriod, and DatesBetween. This chapter will show you the
difference between these two functions and scenarios that you can use each.
DatesBetween and DatesInPeriod both give you a period of dates, but let’s
see their main difference.

Sample Dataset
For examples of this chapter, you need the FactInternetSales table from the
AdventureWorksDW Excel dataset.

DatesInPeriod
The DatesInPeriod function in DAX will give you all dates within a period.
The period can be one of these: Day, Month, Quarter, Year. Here is the
syntax of using this function;
DATESINPERIOD(<dates>,<start_date>,<number_of_intervals>,<interval>)

Here is a description of input parameters;


<dates>: The date field (like many other time intelligence
functions, this function also requires a date field)
<start_date>: The start date that period starts from/to it
(depends if the interval is a positive or negative number)
<number_of_intervals>: a positive or negative number that
starts from the start date based on the interval
<interval>: Year, Quarter, Month, or Day intervals
The output of this function is a table of dates within the period specified.
Let’s see how this function can be used. For example, If you want to get all
dates in the last year’s period from the date of the filter context, it can be a
calculation like this;
DATESINPERIOD(FactInternetSales[OrderDate].[Date],
LASTDATE(FactInternetSales[OrderDate].[Date]),-1,YEAR)

Note that FactInternetSales[OrderDate] is just a regular date field in the


FactInternetSales table, and the reason that I used “.[Date]” at the end of it
is because I am using the built-in date dimension of Power BI. If you use
your date dimension and have set it as a date table, then you should exclude
the “.[Date]” part of this expression. To get the current filter context’s date
as the start date, I used the LASTDATE() DAX function, and we are going a
Year back in the interval. So the number of intervals is –1. The expression
above returns a table and cannot be used as a measure. Just to show you
how this can work, I put it inside another function as a measure.
Example: Sales for the Last Rolling Year
from the current Date
An example of using DatesInPeriod is to calculate the sales of the last year
from the current date. In the expressions above, you’ve seen how we can
get all dates in the period of the previous year from the current date in the
filter context. We need to put it inside a Calculate statement to get the Sum
of Sales for that period.
Sales for the Last Rolling Year =
CALCULATE(
SUM(FactInternetSales[SalesAmount]),
DATESINPERIOD(
FactInternetSales[OrderDate].[Date],
LASTDATE(FactInternetSales[OrderDate].[Date]),
-1,
YEAR)
)
What is the period of the calculation?
The important question in the above calculation is that what is the period of
the calculation? Is this from the first of the year? Or is it starting from a
different date? What is included, and what is excluded? The answer is that;
DatesInPeroid starts from the <start_date> (which in this case is the month
in every row of the table visualized in the screenshot above), and it will go
one year back (because the interval is the year, and the number of intervals
is -1). For example; If the current month April 2007, then it will go one year
back from that date. But does it mean it will start from April 2006, or May
2006? Well, DatesInBetween is a smart function and will exclude the start
date to avoid double counting. It will begin in May 2006. Let’s see what the
period start and period end is.
To get the period start and period end, you can create two measures below
using the FIRSTDATE() and LASTDATE() functions;
First Date in the Period for DatesInPeriod =
FIRSTDATE(
DATESINPERIOD(FactInternetSales[OrderDate].[Date],

LASTDATE(FactInternetSales[OrderDate].[Date]),-1,YEAR)
)

and for the last date;


Last Date in the Period for DatesInPeriod =
LASTDATE(
DATESINPERIOD(FactInternetSales[OrderDate].[Date],
LASTDATE(FactInternetSales[OrderDate].[Date]),-1,YEAR)
)

Now you can see the period clearly in Power BI;


As you can see in the yellow highlighted section, for April 2007, the
Rolling Last Year Sales is $5,994,882.35, between the 1st of May 2006 to
30th of April 2007. As you can see, it starts not from the 30th of April 2006
to avoid double counting. DatesInPeriod makes your like much easier to
calculate dates in a period. That is why it is called DatesInPeriod! So the
value of Rolling Last Year Sales is the accumulation of all sales from May
2006 to April 2007.

DatesInPeriod is the perfect DAX function for calculating


standard periods, which follow Day, Month, Quarter, and
Year intervals. It will exclude unnecessary dates for you.

DatesBetween
DatesBetween function in DAX is a more generic version of DatesInPeriod.
You have more flexibility with this function. With this function, you do not
need to worry about the interval or number of intervals. This function will
give you all the dates between a start date and an end date. Here is the
syntax of this function;
DATESBETWEEN(<dates>,<start_date>,<end_date>)

Parameters are:
<dates>: The date field (like many other time intelligence
functions, this function also requires a date field)
<start_date>: The start date that period starts from it (unlike
DatesInPeriod, this cannot go backward from the start date. It
always go forward from there)
<end_date>: The end date that period ends there.
The output of this function is a table. The table includes dates from the
start_date to the end_date, including both start and end dates.
An important understanding of this function is that the function itself
doesn’t go back or forth from the start date to give you the period. You have
to calculate the start or the end date first and then get the period based on
that. For example, we want to calculate dates in the last rolling year from
the current date in the filter context (similar to the example we have done
with DatesInPeriod). You need first to find out what your start date is.
DATEADD(LASTDATE(FactInternetSales[OrderDate].[Date]),-1,YEAR)

The expression above is using the DATEADD() function. The DateAdd


calculates the start date, which will be a year before (because the interval is
-1) from the start date, which is calculated with LASTDATE().
After calculating the start date, you can use it inside a DatesBetween
function like this;
DATESBETWEEN(FactInternetSales[OrderDate].[Date],
DATEADD(LASTDATE(FactInternetSales[OrderDate].[Date]),-1,YEAR)
,LASTDATE(FactInternetSales[OrderDate].[Date])
)
The first parameter is just the date field. The second parameter is the start
date that we have calculated, and the last parameter is the end date.
DatesBetween is an excellent function to use when the start and end of the
period are determined. Here is an example of calculating the sale of a
specific period.
Sales of Specific Period with DatesBetween =
CALCULATE(
SUM(FactInternetSales[SalesAmount]),

DATESBETWEEN(
FactInternetSales[OrderDate].[Date],
DATE(2007,8,1),
DATE(2007,11,16)
)
)

DatesInPeriod vs DatesBetween
Now let’s see if we use the DatesBetween for calculating the period and get
the start and end of that period what we get as a result;
First DatesBetween =
FIRSTDATE(

DATESBETWEEN(
FactInternetSales[OrderDate].[Date],
DATEADD(LASTDATE(FactInternetSales[OrderDate].[Date]),-1,YEAR)
,LASTDATE(FactInternetSales[OrderDate].[Date])
)
)

and the calculation for the end of the period;


Last DatesBetween =

LASTDATE(
DATESBETWEEN(
FactInternetSales[OrderDate].[Date],
DATEADD(LASTDATE(FactInternetSales[OrderDate].[Date]),-1,YEAR)
,LASTDATE(FactInternetSales[OrderDate].[Date])
)
)

Here is the result compared to DatesInPeriod;


As you can see in the above screenshot, the output of DatesBetween
INCLUDES both start and end dates. It will start from 30th of April 2006,
while the DatesInPeriod begins from 1st of My 2006. so the first difference
between these two functions is that one of them is inclusive of both dates
(DatesBetween).

DatesBetween is a period of dates inclusive of both start


and end dates. DatesInPeriod is giving you the period of
dates and excluding unwanted dates.

Another difference between these two is the input parameters that you have.
Sometimes, you have the start and end date, and you want to get all dates in
that period. DatesBetween is an excellent function to use in this situation.
Sometimes, you do not have both ends of the period; you have one and the
interval. In that case, DatesInPeriod is your best friend. There are many
scenarios that you can use DatesBetween and DatesInPeriod instead of the
other one.

If you have the start and end date, and you want to get all
dates in that period, DatesBetween is an excellent function
to use. However, Sometimes, you do not have both ends of
the period; you have one and the interval; in that
case, DatesInPeriod is your best friend.

Summary
DatesBetween and DatesInPeriod are DAX functions to give you a period
of dates. DatesBetween gives you dates from a start date to an end date.
DatesInPeriod will provide you with an interval of dates from a particular
period. Each function has its usages. You can tweak and change your
expressions with each function to get the same result as the other function
(like anything else in DAX!). However, these two functions will give you
good power in different situations of calculating a period.
Chapter 35: DateAdd vs
ParallelPeriod vs
SamePeriodLastYear; DAX Time
Intelligence Question

Using DAX time intelligence functions for a while; you may ask this
question from yourself that what is the difference between functions below;
SamePeriodLastYear function vs. using ParallelPeriod with
Year parameter
ParallelPeriod for a month vs. DateAdd for a month ago
and many other questions that lead to this final question:
Which function should be used in which situation?
Let’s take a look at these questions and their responses in more detail
through this chapter.

SamePeriodLastYear
Let’s start with the SamePeriodLastYear function; this function will give
you precisely what it explains; same PERIOD but last year! Same period; if
you are looking at data on the day level, it would be the same day the
previous year. If you are slicing and dicing in a month or quarter level, this
will give you the same month or quarter in the last year. You can use the
function simply just by providing a date field:
SamePeriodLastYear(<date field>)

the image below shows how the SamePeriodLastYear works for Date

The SamePeriodLastYear function, like many other time intelligence


functions, needs a date field to work. This is how you can get this function
working:
SAMEPERIODLASTYEAR(DimDate[FullDateAlternateKey].[Date])
The code above returns a table with one single column: date. This is not
returning one single value. This means you cannot use it directly in a
measure. You have to use this function as a filter function. I have used the
SamePeriodLastYear inside a LastDate and a FirstDate. This helps to get
the range of dates for each filter context selection in the screenshot above.
SamePeriodLastYear D To =
LASTDATE(
SAMEPERIODLASTYEAR(DimDate[FullDateAlternateKey].[Date])
)

As you can see in the screenshot above, it shows that the


SamePeriodLastYear returns the same date last year when your filter
context is at the day level. If your filter context is at the month level, you
got the same month the previous year. The screenshot below shows it;

For example, for September 2006, SamePeriodLastYear returns September


2005.

SamePeriodLastYear returns the equivalent period to the


filter context from last year. For 1st of Sep 2006, it will
return date period of 1st of Sep 2005. For Q4 of 2006, it
will return Q4 of 2005. If the filter context is in DAY level,
it will return the same DAY last year. If the filter context is
at the Month level, it will return the same month in the
previous year.

The samePeriodLastYear function, when used in a real-world scenario it


will act as a filter, and you can get the Sales of the same period last year
with that using an expression like this:
Same Period Last Year = CALCULATE(
SUM(FactInternetSales[SalesAmount]),
SAMEPERIODLASTYEAR(
DimDate[FullDateAlternateKey].[Date])
)
ParallelPeriod
ParallelPeriod is another function that gives you the ability to get the
parallel period to the current period. You can navigate to periods in the past
or future. You need three parameters for this function:
ParllelPeriod(<date field>, <number of intervals>, <interval>)
You can choose the interval to be Month, Quarter, or Year. And the number
of intervals can be negative (to go to past) or positive (to go to the future).
This is an example of using ParallelPeriod:

For every month, the ParallelPeriod expression will return a month before
that, because in the parameters, we mentioned the month before:
PARALLELPERIOD(DimDate[FullDateAlternateKey].[Date], -1, MONTH )

ParallelPeriod can be used to fetch the Sales of last month like this:
Parallel Period -1 Month = CALCULATE(
SUM(FactInternetSales[SalesAmount]),

PARALLELPERIOD(
DimDate[FullDateAlternateKey].[Date],
-1,
MONTH)
)

As you can see in the above screenshot, ParallelPeriod will return sales of
the entire last month, even if you are looking at the day level. This brings us
to an important conclusion:

ParallelPeriod results from a period parallel to this period


(in the past or future), which is statically determined in the
Interval parameter; Can be Month, Quarter, or Year.
Understanding this fact; now we can answer this question:

What is the difference between


SamePeriodLastYear and ParallelPeriod?
The first difference is that ParallelPeriod gives you the option to go as many
intervals as you want back or forward. If you're going to get the sales for
last months, then ParallelPeriod is your friend. For calculating the sales of 2
years ago, then ParallelPeriod is your friend.
Dynamic Period is another difference between these two functions; If you
think that the result of SamePeriodLastYear and the ParallelPeriod (when it
is used with Year interval) are the same, continue reading. Below is an
example of these two measures:
For August 2006, for example, the SamePeriodLastYear gives us the sales
of August 2005. However, the ParallelPeriod with year interval returns the
sales for the entire year 2005.

DateAdd
DateAdd is a function that adds or subtracts some
days/months/quarters/years from or to a date field. DateAdd can be used
like this:
DateAdd(<date field>, <number of intervals>, <interval>)

DateAdd used in a example below to return the period for a month ago.
DateAdd can be used in a Day level too. This brings us to the first
difference of ParallelPeriod and DateAdd;

DateAdd can work on an interval of DAY, Month, Quarter,


or Year, but ParallelPeriod only works on intervales of
Month, Quarter, and Year.

This is the example expression to calculate the sales for yesterday:


DateAdd -1 Day = CALCULATE(
SUM(FactInternetSales[SalesAmount]),

DATEADD(
DimDate[FullDateAlternateKey].[Date],
-1,
DAY))

DateAdd vs ParallelPeriod
Comparing these two functions with each other, you can see that DateAdd
works on the period dynamically (like SamePeriodLastYear), but the
ParallelPeriod works statically on the interval mentioned as the parameter.
That leads us to conclude that DateAdd(<date field>,-1, Year) is similar to
SamePeriodLastYear. However, one difference is still there:

DateAdd vs SamePeriodLastYear
SamePeriodLastYear only goes one year back. DateAdd can go two years
back or even more. DateAdd is a customized version of
SamePeriodLastYear.
Conclusion
In summary, there are differences between these three functions:
DateAdd and SamePeriodLastYear both work based on the
DYNAMIC period in the filter context
ParallelPeriod is working static, based on the interval selected
in the parameter
ParallelPeriod and DateAdd can go more than one interval
back and forward, while SamePeriodLastYear only goes one
year back.
DateAdd works on the interval of DAY and month, quarter,
and year, but ParallelPeriod only works on month, quarter, and
year.
Depends on the filter context, you may get a different result
from these functions. If you get the same result in a year-level
context, it doesn’t mean that all these functions are the same!
Look more into the detailed context.
Chapter 36: Same Period Last Year
to Date DAX Calculation in Power
BI

In previous chapters, you learned about the SamePeriodLastYear and year-


to-date functions. However, sometimes, you don’t yet have the whole year,
especially for the current year. You might want to compare this year’s value
with the last year’s value until the same day but last year. This is what I call
the same period last year to date. Here in this chapter, I’ll explain how you
can do that using DAX in Power BI.
Explaining the Problem
Let’s say I have a same period last year calculation like this:
Sales SPLY = CALCULATE(
[Sales],
SAMEPERIODLASTYEAR(DimDate[FullDateAlternateKey].[Date])
)

This calculation works perfectly as a measure, as long as we are dealing


with full periods:

The problem, however, appears when we do not have a full year like below;
In the above screenshot, we have only sales up until July 2008. The same
period last year's calculation at the month level is correct for that period
itself (month level). However, for the whole quarter is not, because if I am
comparing Qtr 3 of 2008, I have one month of sales there (July 2008).
However, in Qtr 3 of 2007, because we have sales of all months (July,
August, and September 2007), the two values are not comparable. This
leads to a wrong year-over-year calculation too.

The Solution
The correct calculation would be finding the last date that we have sales on,
then find the same date but last year, and then calculate the sales of the
same period last year up until that day. Like anything else in DAX, there are
multiple ways of doing this. Here is one method explained below.
Last date of sales
I am using the below expression to find what is the last date that we have
any sales:
var lastdateAvailable=CALCULATE(MAX(FactInternetSales[OrderDate]),ALL(FactInternetSales))

Having the ALL helps me find the last date from the sales table regardless
of the filter context in the visual.
A year before that
Now that we have the last date of the sales, we can go one year back. I use
the below approach;
var lastyearsameday=lastdateAvailable-365

Check for Leap Year


If there is a leap year in between this period, then the calculation above is
wrong, so I added the below part to check for that and get the correct value
regardless:
var ifLY=IF(DAY(lastyearsameday)<>DAY(lastdateAvailable),TRUE(),FALSE())
var lastyearsamedayLY=IF(ifLY,lastdateAvailable-366,lastyearsameday)

Same Period Last Year filtered up until that day


We have all the elements now. Using the SamePeriodLastYear combined
with Filter, we can get only part of the period before the date we calculated
in the previous step.
var SPLYUntillastdate=FILTER(
SAMEPERIODLASTYEAR(DimDate[FullDateAlternateKey].[Date]),
DimDate[FullDateAlternateKey].[Date]<=lastyearsamedayLY)

Full expression
Here is the full expression:
Sales SPLY to Date - Considering Leap Year =
var lastdateAvailable=CALCULATE(MAX(FactInternetSales[OrderDate]),ALL(FactInternetSales))
var lastyearsameday=lastdateAvailable-365
var ifLY=IF(DAY(lastyearsameday)<>DAY(lastdateAvailable),TRUE(),FALSE())
var lastyearsamedayLY=IF(ifLY,lastdateAvailable-366,lastyearsameday)
var SPLYUntillastdate=FILTER(
SAMEPERIODLASTYEAR(DimDate[FullDateAlternateKey].[Date]),

DimDate[FullDateAlternateKey].[Date]<=lastyearsamedayLY)
return
CALCULATE(
[Sales],
SPLYUntillastdate)

Testing the results


Here is the result of the expression now:
As you can see, the above calculation only calculates rows up until the
same day but last year. The quarter calculation and yearly calculation are
also aggregating that correctly. Compared to values marked red above,
which incorrectly calculates the entire period, this calculation works
perfectly fine for comparing this year vs. last year.
Note that, like anything else in DAX, this calculation can be done in many
other ways too. This method is only one of the many possible options.
Chapter 37: Week to Date
Calculation in Power BI with DAX

Many businesses work on a weekly period rather than monthly. So here in


this chapter, I will explain a method to do a week-to-date calculation with
DAX.

Introduction
There is a set of functions for calculating Year to Date (TotalYTD), Quarter
to Date (TotalQTD), and Month to Date (TotalMTD). However, for
calculating Week to Date, there is no built-in function. There are many
ways to calculate week to date. One method uses functions such as
DatesBetween and WeekDay to calculate the period between the first day of
the week and the filter context. Let’s see how it works.

Sample Dataset
If you want to use this example, create a Power BI file connected to
AdventureWorks data source and load FactInternetSales, and DimDate into
the model. Create a connection between these two tables based on DateKey
(from DimDate) and OrderDateKey (from FactInternetSales).

Mark As Date Table


* for a week-to-date calculation to work, it is not mandatory to have a date
table. You can even use the built-in date table of Power BI. all the below
calculations would work even if you use the built-in date table. You need to
add .[date] at the end of your date field to get it working.
Because in this example, we will use DimDate as our date table, select this
table in the list of fields (in report tab or data tab), and mark it as a date
table.
Select FullDateAlternateKey as the date column.

Create a table visual with CalendarYear, EnglishMonthName,


DayNumberOfMonth, and EnglishDayNameOfWeek, and SalesAmount
WeekDay DAX Function
Let’s first find out the day number of the week for any given date to start
the solution. We already have the day number of the week in the DimDate
provided by AdventureWorks. However, we calculate it again, just in case
you use the built-in date table. Using the LastDate function, we get the date
value of the current filter context and wrap it inside a WeekDay function to
fetch the day number of the week. Here is the DAX statement:
Day Number of Week = WEEKDAY(LASTDATE(DimDate[FullDateAlternateKey]))

This measure would be the day number of the week. Starting from Sunday
as 1, ending Saturday as 7.
Starting from Monday
Not always in all businesses, the week starts from Sunday. In fact, in many
companies, the week begins on Monday. WeekDay function has a second
parameter that can determine the starting day of the week. The parameter
name is Return Type.

The default value is 1. means Sunday is 1, and Saturday 7.


If you change it to 2, Monday will be 1, and Sunday 7.
If you change it to 3, Monday will be 0, and Sunday 6. This one will appeal
more for the rest of our calculation. Set this parameter to 3.
Day Number of Week = WEEKDAY(LASTDATE(DimDate[FullDateAlternateKey]),3)

Start of the Week


Now that we know the day of the week, it is easy to calculate the start of the
week. You need to go that number back as a day's interval. For example,
Wednesday is day 2 of the week. If you go two days back, you get Monday.
Using the DateAdd function, you can go as many days back you want. here
is the DAX expression:
Start of Week =
var CurrentDate=LASTDATE(DimDate[FullDateAlternateKey])
var DayNumberOfWeek=WEEKDAY(LASTDATE(DimDate[FullDateAlternateKey]),3)
return
DATEADD(
CurrentDate,
-1*DayNumberOfWeek,
DAY)

The heart of the expression above is the DateAdd calculation. We go the


number of days back (that is the reason for -1*DayNumberOfWeek). Here
is the result. For every given date, we get the Monday (which is the start of
that week) of that week as the week's start date.

Week to Date Calculation


Now that we have the start of the week, we can calculate all dates between
that date and the current filter context using DatesBetween, and wrap it
inside a calculate to calculate Week to Date.
DATESBETWEEN(
DimDate[FullDateAlternateKey],
DATEADD(

CurrentDate,
-1*DayNumberOfWeek,
DAY),
CurrentDate)

DAX expression above is using DatesBetween to give us all dates between


the start of the week (calculated in the previous step) and the date of the
current filter context (LastDate(DimDate[FullDateAlternateKey])).
We can then wrap it inside a Calculate function to get the week to date as
below;
Week to Date Sales =
var CurrentDate=LASTDATE(DimDate[FullDateAlternateKey])
var DayNumberOfWeek=WEEKDAY(LASTDATE(DimDate[FullDateAlternateKey]),3)
return
CALCULATE(
SUM(FactInternetSales[SalesAmount]),
DATESBETWEEN(
DimDate[FullDateAlternateKey],
DATEADD(
CurrentDate,
-1*DayNumberOfWeek,

DAY),
CurrentDate))

Here is the result;


Just for a reference, here is the entire Week to Date calculation with DAX
again:
Week to Date Sales =
var CurrentDate=LASTDATE(DimDate[FullDateAlternateKey])
var DayNumberOfWeek=WEEKDAY(LASTDATE(DimDate[FullDateAlternateKey]),3)
return
CALCULATE(
SUM(FactInternetSales[SalesAmount]),
DATESBETWEEN(
DimDate[FullDateAlternateKey],
DATEADD(
CurrentDate,
-1*DayNumberOfWeek,
DAY),
CurrentDate))
Chapter 38: Calculate Duration in
Days Hours Minutes and Seconds
Dynamically in Power BI using
DAX

In Power Query, there is an easy way to use Duration and get the number of
days, hours, minutes, and seconds from it. However, sometimes you need
this calculation to be dynamic as a measure in DAX. I had that requirement
too. And I wrote a simple DAX calculation which will give you the result.

You have the duration in Minutes and


want to calculate Hours/Minutes
If you have the duration in Minutes and want to calculate it in hours and
minutes. This is a DAX measure that can help with that.
*Note: The [Duration in Minutes] part of the expression below should be
replaced with the value/field/measure you have the minutes coming from it.
String Duration in Hours and Minutes =
var vMinues=[Duration in Minutes]
var vHours=int( vMinues/60)
var vRemainingMinutes=MOD(vMinues, 60)
return

vHours&" Hours & "& vRemainingMinutes& " Minutes"

And here is the result:

You have the duration in Seconds and


want to calculate Hours/Minutes/Seconds
If you have the duration in seconds and want to have a result that tells you
how many hours, minutes, and seconds you have in total. Here is the
expression for that.
*Note: The [Duration in Seconds] part of the expression below should be
replaced with the value/field/measure you have the seconds coming from it.
String Duration in Hours Minutes and Seconds =
var vSeconds=[Duration in Seconds]
var vMinutes=int( vSeconds/60)
var vRemainingSeconds=MOD(vSeconds, 60)
var vHours=INT(vMinutes/60)
var vRemainingMinutes=MOD(vMinutes,60)
return
vHours&" Hours & "&
vRemainingMinutes&" Minutes & "&
vRemainingSeconds& " Seconds"

And the result looks like this:


You have the duration in Seconds and
want to calculate
Days/Hours/Minutes/Seconds
If you're going to also add days to the total, which would look like: “x”
days, “y” hours, “z” minutes, and “s” seconds. then you can use the
expression below:
*Note: The [Duration in Seconds] part of the expression below should be
replaced with the value/field/measure you have the seconds coming from it.
String Duration in Days Hours Minutes and Seconds =

var vSeconds=[Duration in Seconds]


var vMinutes=int( vSeconds/60)
var vRemainingSeconds=MOD(vSeconds, 60)
var vHours=INT(vMinutes/60)
var vRemainingMinutes=MOD(vMinutes,60)
var vDays=INT(vHours/24)
var vRemainingHours=MOD(vHours,24)
return
vDays&" Days & "&
vRemainingHours&" Hours & "&
vRemainingMinutes&" Minutes & "&
vRemainingSeconds& " Seconds"

The result will look like this:


Why not calculate the duration in Power
Query?
If you have worked with Power Query, you might know a much easier way
to calculate these from a duration data type in Power Query. However,
Power Query does all the calculations as pre-calculated. Sometimes you do
need these to be dynamically calculated in Power BI using DAX. Like the
example below, you might want to choose the date range of a timesheet and
see in total how many days, hours, minutes, and seconds have been
recorded.
Chapter 39: Previous Dynamic
Period DAX Calculation

The ParallelPeriod is a function that helps you fetching the previous period
of a Month, Quarter, or Year. However, if you have a dynamic range of
date, and you want to find the previous period of that dynamic selection,
then Parallel Period can’t give you the answer. As an example; if the user
selected a date range from 1st of May 2008 to 25th of November 2008, the
previous period should be calculated based on the number of days between
these two dates, which is 208 days, and based on that previous period will
be from 5th of October 2007 to 30th of April 2008. The ability to do such
calculation is helpful for reports that users want to compare the current
period's value with whatever period it was before this. In this chapter, I’ll
show you an easy method for doing this calculation. I will be using one
measure for each step to help you understand the process easier.

Current Period
I will go through this with an example; Create a new Power BI Desktop file
and choose DimDate and FactInternetSales from AdventureWorksDW.
Ensure that there is only one Active relationship between these two tables
based on OrderDateKey in the FactInternetSales table and DateKey in the
DimDate table. Now add a slicer for FullDateAlternateKey on the page

Also, add a Card visual that shows SalesAmount from the FactInternetSales
table.

I usually prefer to create an explicit measure for this type of calculation.


That’s why I have created a measure named “This Period Sales” with the
DAX code below; (the measure for This Period Sales is not necessary
because Power BI does the same calculation automatically for you)
This Period Sales = SUM(FactResellerSales[SalesAmount])

Start of Current Period


An easy way to understand the current period is by calculating the start, end
of the period, and the number of days between these two. The start of the
Period is simple. I create a measure under DimDate, as below:
Start of This Period = FIRSTDATE(DimDate[FullDateAlternateKey])

Date() DAX function returns the first available date in the current
evaluation context, whatever filtered in the date range.
End of Current Period
Same as the start of the period, I will use a simple calculation for the end of
the period, but this time with LastDate() to find the latest date in the current
selection.
End of This Period = LASTDATE(DimDate[FullDateAlternateKey])

Days in This Period


The following easy step is understanding the number of days between start
and end of the period, which is simply by using DateDiff() DAX function as
below;
Days in This Period = DATEDIFF([Start of This Period],[End of This Period],DAY)

I add them all in the report as Card Visuals (one for each measure), and here
is the result so far;

Previous Period
After finding the number of days in this period, start, and end of the current
period, it is a simple calculation to find the previous period. The previous
period calculation should be the number of days in this period minus the
start of the current period. To exclude the start of the period to calculate
twice, I’ll move one more day back. Here is the calculation step by step. I’ll
start with the Start of the Previous Period;
Start of Previous Period
Using DateAdd to reduce the number of days from
DimDate
DATEADD(DimDate[FullDateAlternateKey],-1*[Days in This Period],DAY)

DateAdd() DAX function adds a number of intervals to a date set. In this


example, the interval is DAY, and the date set is all dates in
DimDate[FullDateAlternateKey] field (because DateAdd doesn’t work with
a single date). The number of intervals is Days in This Period multiplied by
-1 (to move dates backward rather than forward).

Fetch the First Date of the result


FIRSTDATE(DATEADD(DimDate[FullDateAlternateKey],-1*[Days in This Period],DAY))

FirstDate() is used here to fetch the first value only.


Move one day back
PREVIOUSDAY(FIRSTDATE(DATEADD(DimDate[FullDateAlternateKey],-1*[Days in This
Period],DAY)))

To exclude the current date from the selection, we always move one day
back. That’s what PreviousDay() DAX function does. It always returns a
day before the input date.
These are not three separate DAX expressions or measures. This is only one
measure which I explained step by step. Here is the full expression:
Start of Previous Period =
PREVIOUSDAY(FIRSTDATE(DATEADD(DimDate[FullDateAlternateKey],-1*[Days in This
Period],DAY)))

End of Previous Period


Similar to the Start of Previous Period calculation, this calculation is the
same. The only difference is using LastDate();
End of Previous Period =
PREVIOUSDAY(LASTDATE(DATEADD(DimDate[FullDateAlternateKey],-1*[Days in This
Period],DAY)))

Days in Previous Period


You don’t need to create this measure. I have only created this to do a check
and see if I have the same number of days in this period compared with the
previous period or not;
Days in Previous Period = DATEDIFF([Start of Previous Period],[End of Previous Period],DAY)

Now, if I add all of these measures to the report with card visuals again, I
can see previous period calculation works correctly;

With every change you apply in the date range slicer, you can see the
previous period calculates the range again. It will always be the same
number of days as the current period, but the same number of days
BEFORE. In the screenshot above, you can see that the start of the previous
period is 321 days before starting this period. One more day because the
end of the previous period is not exactly the start of this period. It is one day
before. We don’t want to duplicate values of date in current and previous
calculations.

Previous Period Sales


Now as an example I have created another measure to show you the sum of
SalesAmount for the previous period. the calculation here uses
DatesBetween() DAX function to fetch all the dates between start of
previous period and end of previous period;
Previous Period Sales = CALCULATE(SUM(FactResellerSales[SalesAmount])
,DATESBETWEEN(
DimDate[FullDateAlternateKey],

[Start of Previous Period],


[End of Previous Period]),
ALL(DimDate) )

Showing all of these in a page now;

Summary
This chapter showed you a useful DAX calculation to find Dynamic
Previous Period based on the date range selection in the Power BI report
page. I have used number of DAX functions such as FirstDate(),
LastDate(), DateAdd(), DateDiff(), and PreviousDate() to do calculations.
Calculation logic calculates the number of days in the current period and
reduces it from the start and end of the current period to the previous
period.
Part 7: Table manipulation
functions
Chapter 40: Creating a Table in
Power BI Using DAX Table
Constructor

There are some functions in DAX that are useful in particular scenarios. For
example, sometimes, you might want to create a table entirely in DAX. If
you're going to do that, what are your ways, and how is it possible? This
might be helpful, especially in the first days of learning about DAX. Let’s
see how the table constructor can help you to do that.

Table Constructor
Table constructor is not a function in DAX. It is a set of characters which
you can create a table in DAX by them. Table instructor is always
surrounded by {} characters. The syntax of the table constructor is simple.
It is like below:
{<value1>,<value2>...}
This means value1 will be the value of the first column in the table, value2
would be the value of the second column, etc.
if you want to have more rows, you can separate them with
parenthesis () and a comma, like this:
{
(value1,value2,...),
(value1,value2,...)

Let’s Experiment
Create a new Power BI Desktop file. And then, in the Modeling tab, click
on New Table.

In the table expression, you can write:


Sample Table = {1}

This will create a table called Sample Table, with one single column called
“Value”, and the value in the only row for that would be 1. The Value
column automatically takes the data type of the Whole Number.
If you use an expression like this with parenthesis;
Sample Table = {(1)}
You would still get the same output:

If I want a table with two or three rows, I can try this expression:
Sample Table = {1,2,3,4}

As you see, even the comma separates the rows. However, what if we want
to have more columns? In that case, you need to use parenthesis to bundle
them together in one row. Like this:
Sample Table = {(1,2,3,4)}

If you want to have multiple rows and columns in the table, you can write
an expression like this:
Sample Table = {(1,2),(3,4)}
This will create a table with two columns: value1, and value 2, and two
rows as below;

Values in each cell can be anything, here is another example:


Sample Table = {
(1,"the first row",DATE(2019,1,1)),
(3,"the second row",Date(2020,5,12))
}

And Power BI automatically sets the columns data types to Whole Number,
Text, and DateTime;
With the table constructor, you can have different data types in each
column, but then, Power BI converts all values to a common data type. Like
below example;
Sample Table = {
(1,"the first row",DATE(2019,1,1)),
(3,"the second row",12),

(3,"the second row","something")


}

Limitations
When you are using constructors, you can put any values you like as the
values of cells and rows. However, all rows should have the same number
of columns. For example, the below expression won’t work:
Sample Table = {
(1,"the first row",DATE(2019,1,1)),
(3,"the second row",),
(3,"the second row","something")
}

The second row in this sample is missing the third column:

And that is why you get the error: Each tuple in the table constructor must
have the same number of columns.
If you want to pass a cell with no value, you can either leave that part blank
or use the BLANK() function. Like the below example:
Sample Table = {
(1,"the first row",DATE(2019,1,1)),
(3,"the second row",),
(3,"the second row","something")
}
Column names are always Value1, Value2, Value3, etc., and you cannot
change them in the table constructor. You can, however, change it afterward
by just renaming it or even using the SelectColumns function. Data types of
columns are defined automatically, which you can then go and adjust
manually. Because of these two limitations, I’d instead use
the Datatable function in DAX, giving us more options and flexibility.

Summary
Table constructor is a fast and straightforward way of creating tables in
DAX if you need it. However, this method has some limitations on the
column names and the data types, making the Datatable function a better
replacement if you want more customization.
Chapter 41: Using DataTable DAX
Function for Creating Structured
Table in Power BI

In the previous chapter, you learned how easy it is to use a table constructor
in DAX to create a data table fast in Power BI. However, that method has
some limitations, such as not naming columns or setting their data types.
This chapter will explain the DataTable function in DAX, giving us more
flexibility to set column-specific structures. Let’s see how this can be used.

DataTable Function
Datatable is a function in DAX to create a table. The syntax allows you to
define each column name and data type and then add data values. Here is
the structure of a Datatable function usage:
Sample Table = DATATABLE(
"column 1 name",<data type>,
"column 2 name",<data type>,
{
{<value row 1 col 1>,<value row 1 col 2>},
{<value row 2 col 1>,<value row 2 col 2>}
}
)

The minimum things you need for this function to work is at least one
column, plus one row, which can be used like this:
Sample Table = DATATABLE(
"First Name",STRING,
{
{"Reza"}
}
)
The part inside {} is the data rows. And each row itself is in another {}. So,
if I want to add two rows, it would be like this:
Sample Table = DATATABLE(
"First Name",STRING,
{
{"Reza"},
{"Leila"}
}
)
To add more columns to this table, you can just add another line of name
and data type before the first {}. Similar to below;
Sample Table = DATATABLE(
"First Name",STRING,
"Last Name",STRING,

{
{"Reza"},
{"Leila"}
}
)

However, the above expression won’t work like that because we still have
one value in every row.
You need to have the same number of values in each row. However, the
blank itself is also considered as value. Blank can be represented with
BLANK() or with no value in a place holder.
Sample Table = DATATABLE(

"First Name",STRING,
"Last Name",STRING,
{
{"Reza","Rad"},
{"Leila","Etaati"},
{"someone",},
{"Unknown",blank()}
}
)
You can see that both 3rd and 4th rows are blank in their “Last Name”
column but defined differently in the expression.
The data type of each column can be one of the below types: Integer,
Double, String, Boolean, Currency, and DateTime
If a value is specified in a data value that is not of the column's data type,
the type conversion will happen. Like what you see below that occurs on
the “0” in the 3rd column of the first row;
Sample Table = DATATABLE(
"First Name",STRING,
"Last Name",STRING,
"Time",DATETIME,
{

{"Reza","Rad",0},
{"Leila","Etaati",},
{"someone",,"2019-2-10"},
{"Unknown",blank(),"2019-2-10"}
}
)
You can specify column names with special characters in them, such as
below. However, if you want to use ” (double quote) in your column name,
you need to use another double quote as an escape character for it.
Sample Table = DATATABLE(
"1First Name",STRING,
"@Last Name",STRING,
"""Time",DATETIME,
{
{"Reza","Rad",0},
{"Leila","Etaati",},
{"someone",,"2019-2-10"},
{"Unknown",blank(),"2019-2-10"}

}
)

Adding Expression-based Columns


If you want to add expression-based columns to your table, The best would
be to use other functions such as SelectColumns, AddColumns, or
SummarizeColumns (Depends on what exactly you want to do). Here is an
example of adding a Full Name column to our sample table:
Sample Table =
ADDCOLUMNS(
DATATABLE(

"First Name",STRING,
"Last Name",STRING,
"Time",DATETIME,
{
{"Reza","Rad",0},
{"Leila","Etaati",},
{"someone",,"2019-2-10"},
{"Unknown",blank(),"2019-2-10"}
}

),
"Full Name",[First Name]&" "&[Last Name]
)

Limitation
If you use Table Constructor to build a table, you can use any expression as
the value. Here is an example that uses the time now() function as a value in
a data cell using table constructor:
Table = {(now())}

However, you cannot use that in Datatable function;


Sample Table =
DATATABLE(
"Sample Time",DATETIME,
{

{now()}
}
)

You will get the error: The tuple at index ‘1’ from the table definition of the
DATATABLE function does not have a constant expression in the column at
index ‘1’.

The value in each cell can be only constant, not any scalar expression.
An alternative would be using SelectColumns, AddColumns, or other
methods to get an expression-based column added to the table.

Another Method: Table Constructor


In the previous chapter, I have explained an easier and faster way
of creating a table using Table Constructor in DAX for Power BI. If the
column names and data types are not necessary for your scenario, you can
follow that approach.

Summary
There are different ways to create a table in Power BI using DAX. Using
the Datatable function will give you flexibility in defining each column
name and data type specifications. At the same time, the table constructor is
just an easy and fast way of creating a data table with no specific metadata
setup. The syntax of the Datatable function is explained in the screenshot
below:
Chapter 42: Some Simple Ways to
Debug Your DAX Measure Code in
Power BI: Debugging Virtual
Tables

Debugging DAX codes can sometimes be a bit of a challenge, especially


because measures are dynamic, and you won’t see their values in the data
tab of Power BI. You will see their value when they are evaluated in a
visual. Because sometimes measures use nested functions and tables, the
whole process of debugging DAX code becomes even more complicated. In
my training sessions, many people consider DAX as a complicated
language to learn is the hardship of debugging it. So here, in this chapter, I
am explaining some simple ways to debug your DAX expression in Power
BI.

Introduction: Why Hard to Debug?


If you write a simple DAX expression like below:
Sum(FactInternetSales[SalesAmount])
Then the expression looks simple. However, it is a bit challenging to find
the context in which this expression will be calculated. For calculated
columns, the debug process is easier most of the time because the context
that the calculated is evaluated is a row by row context (calculation happens
for one row each time). However, even that has exceptions. When it comes
to measures, the whole thing becomes more challenging because you don’t
know how the calculation will be before putting it on a report page.

In addition to the context in which the DAX expressions apply, often in


DAX expressions, we use virtual tables. Here is what I mean by virtual
table:
What do I mean by Virtual Table in DAX?
There are some functions and calculations in DAX that return a table. If you
use those functions to create a calculated table, you have an actual table in
Power BI. One of these functions is the ALL() for example, I have written a
whole chapter about use cases of that earlier in this book. Other examples
of this function are SamePeriodLastYear, DatesInPeriod, DatesBetween,
and many other functions that all return table instead of a single value. I am
not saying that those functions are producing virtual tables. Here is what I
mean by a virtual table.

If a function or calculation produces a table as output, and


it is used directly in a DAX expression as an input for
another function, you don’t see that table's content. That
table is what I call a virtual table.

I call this virtual table, some others call it with all other different names,
and some event doesn’t call it anything but use it. The fact is that in DAX, it
is very common that you use nested functions. Here is a straightforward
example of the usage of nested tables or virtual tables:

The ALL(FactInternetSales) function is not a real table. It is a table nested


into another function. It is a virtual table inside a DAX expression.

How to see the content of Virtual tables


One of the hardships of debugging a DAX code is finding out the data in
the virtual table. The virtual table is not an actual table that you can see the
content of it. It is not also a single value that you can put in a measure and
see the outcome. it is a whole table with columns and rows. And you cannot
show a table in a measure as output:
The All is probably one of the easiest functions to find the context because
it ignores the filter, but the process can be much more complicated for other
scenarios or functions. I have a set of simple methods that I use to debug a
virtual table in DAX. Let’s see what these are. As an example, we can see
how they work with a sample. Let’s say I want to know how the
SamePeriodLastYear function work. Our goal is not to find the difference in
this chapter but to see how we can debug that code).
Produce Single Value Output from the Virtual
Table
Because it is impossible to show the whole table in a measure, you have to
find ways to get single values from it, but single values can give you an
idea of what is in the table. Some methods can be like getting the first value
of the table, the last value, the concatenated list, or the count of rows in the
table.
The table that you see in the screenshot above is not a virtual table. It is a
real table. However, the process to understand the virtual table’s content is
the same. When you use methods to get the first value of the column in the
table, or the last value, or count of rows, or concatenated list, or any
combination of these and any other values, you get a feeling of the content
of the nested table.
Let’s say I have a measure like this:
Same Period Last Year = CALCULATE(
SUM(FactInternetSales[SalesAmount]),
SAMEPERIODLASTYEAR(

DimDate[FullDateAlternateKey].[Date]))

The part that is not clear for me in the expression is what is the period of
the SamePeriodLastYear(DimDate[FullDateAlternateKey].
[Date])?
Because I don’t see that table, I can use methods like this to get that value:
The First Value
I create a new Measure and also use variables to get the virtual table into
that, then using the FirstDate() function in DAX, I get the first Value of it:
Same Period Last Year Debug =
var vTable=SAMEPERIODLASTYEAR(
DimDate[FullDateAlternateKey].[Date])

return
FIRSTDATE(vTable)

Here is the output:


As you see, for any given date in the context of the table, like October
2006, I can see that my virtual table (the table created by
SamePeriodLastYear function) is starting from the 1st of October for that
year.
Using variables can be sometimes tricky. You can achieve the same thing
even without variables too. Also, because my values in the virtual table are
dates, I used the FirstDate function to get the first value. You can also
use FirstNonBlank or Min depends on the data type.

The Last Value


I can use the same method to produce the last value,
using LastDate, LastNonBlank or Max.
Same Period Last Year Debug =
var vTable=SAMEPERIODLASTYEAR(
DimDate[FullDateAlternateKey].[Date])
return
LASTDATE(vTable)

Or even better, you can combine the two (first and last value):
Same Period Last Year Debug =
var vTable=SAMEPERIODLASTYEAR(

DimDate[FullDateAlternateKey].[Date])
return
FIRSTDATE(vTable)&" - "&LASTDATE(vTable)

This gives you a clear idea of values in that table because you have the first
and the last value visualized now.
The Row Count
Another helpful function that I use often is the CountRows. You can also
use Count, or CountX, or other variations of it. This gives you information
about how many rows you have in that table.

Concatenated Values
Most of the times, I get what I want with only using the first, the last, and
the count. However, sometimes, you might need to see every individual
value and how they ordered. ConcatenateX is a very good function for that.
It gives you those values as a string concatenated value. like this:
Same Period Last Year Debug =
var vTable=SAMEPERIODLASTYEAR(
DimDate[FullDateAlternateKey].[Date])
return
FIRSTDATE(vTable)&" - "&LASTDATE(vTable)
&" - Row Count: "&COUNTROWS(vTable)

&" - Values: "&CONCATENATEX(vTable,DimDate[FullDateAlternateKey].[Date],",")


There are many other methods that you can use to get the feeling of what
values you have in your virtual table. Methods you have seen here are
methods that I use often.

Summary
Inline, nested, or virtual tables in DAX is one of the structures that is a bit
of a challenge to debug. The trick for those is to produce a single value
output of those tables for debug purposes. This method gives you an
understanding of what you have in that table. In this chapter, you have seen
how it is simply possible with simple functions such as FirstDate or
FirstNonBlank, LastDate or LastNonBlank, CountRows, and ConcatenateX
to achieve that goal.
Chapter 43: How to use
AddColumns function in DAX and
Power BI

AddColumns is a DAX function that is often helpful when writing


calculations in Power BI. This chapter will explain how you can use it to
add calculated columns on the fly to the virtual tables in measures or
directly in a table.

AddColumns DAX Tabular Function


AddColumns is a tabular function in DAX. It means it returns a table,
not a value. Tabular functions cannot be used directly in a measure, they
have to be embedded inside other functions, or they can be used as a table
expression.
The signature of using this function is as below;
ADDCOLUMNS(<table>, <name>, <expression>[, <name>, <expression>]…)

Table: the table that we want to add columns to it


Name: the name of the new calculated column
Expression: the expression of the new calculated column
you can add multiple columns using this function.
As an example, I can use the function to add a column to the customer
table;
add col example = ADDCOLUMNS(
DimCustomer,
'Total revenue from the customer',
CALCULATE(

SUM(FactInternetSales[SalesAmount]),
RELATEDTABLE(FactInternetSales)
)
)

The code above adds a new column to the DimCustomer, named “Total
revenue from the customer”. The expression for this new calculated column
is the CALCULATE part of the expression above.
The above expression can be written as a new table in Power BI;
AddColumn DAX function in Power BI
You can use the AddColumns to add more than one column, like below;
ADDCOLUMNS(
DimCustomer,
'Total revenue from the customer',
CALCULATE(
SUM(FactInternetSales[SalesAmount]),
RELATEDTABLE(FactInternetSales)

),
'Order Count',
COUNTROWS(
RELATEDTABLE(FactInternetSales)
)
)
The code above adds two columns to the DimCustomer table;

AddColumns used to add more than one column

AddColumns in virtual tables


You can use AddColumns to create a calculated table (such as the examples
above or making a date table using DAX). However, the most common way
of using it is to use it inside a measure. Because AddColumns is a tabular
function, to use it in a measure, you need other functions too.
Because AddColumns returns a table, the result can be used to input another
function that accepts a table.
For example, let’s say we want to draw a customer for a weekly prize draw
randomly. To randomly the customer, one way is to add a random number
to each customer and then pick the customer with the highest random
number.
The expression below adds a column to DimCustomer with a Random
number between 0 to 1 (generated by RAND());
var customers=ADDCOLUMNS(
DimCustomer,
'Rand',
RAND())

Now the result of the expression above is in a table variable. You can use
that to pick the one with the highest random value;
var one_Customer=TOPN(1,customers,[Rand],DESC)

As you can see, the TOPN function uses the result of AddColumns (the
customers variable) as the input table.
and finally, we can return the customer’s full name for that one customer;
CONCATENATEX(one_Customer,[FullName])

Altogether, the expression for the measure is like below;


Draw a customer =
var customers=ADDCOLUMNS(
DimCustomer,
'Rand',
RAND())
var one_Customer=TOPN(1,customers,[Rand],DESC)
return
CONCATENATEX(one_Customer,[FullName])
AddColumns used to draw a random record
If you run the code above on the same dataset, you would likely get another
customer because the rand() function generates different values each time.
There are at least a dozen other ways to fetch a random record from a table.
This example here is just provided to show you how AddColumns works
inside a measure.
If you are interested in learning another real-world example of using
AddColumns inside a measure, look at my example of Dynamic Row-level
security using many-to-many and hierarchical
scenarios here[https://radacad.com/dynamic-row-level-security-in-power-
bi-with-organizational-hierarchy-and-multiple-positions-in-many-to-many-
relationship-part-2].

Summary
AddColumns is a DAX function that returns a table. The returned table
includes all the columns from the input table plus the new calculated
columns. The expression written for the AddColumns will run for every
row in the input table and generates the new column using it.
AddColumns is a table manipulation function, it does not change the
existing rows and columns, but it adds new columns.

AddColumn in DAX and Power BI adds new columns to the existing table
AddColumns can be used to create a calculated table. But the primary usage
of that is inside measures to add columns to a virtual table.
Chapter 44: Create a subset of the
table in Power BI and add
calculations using
SELECTCOLUMNS DAX
Function

Previously I explained the AddColumns function as a function that adds one


or more columns to the existing table. This chapter will describe another
similar and useful function with slightly different behavior: SelectColumns,
and you will learn how you can use it in Power BI and DAX.

SELECTCOLUMNS is a Tabular function


in DAX
Similar to the AddColumns and many other functions, SELECTCOLUMNS
is a tabular function in DAX, which means it returns a table as a result.
Tabular functions are used a lot inside other functions when writing a
measure.
The signature of the SelectColumns function is as below;
SELECTCOLUMNS(<table>, <name>, <scalar_expression> [, <name>, <scalar_expression>]…)

Table: the table.


Name: Name of the new column added
Expression: The expression for the new column
you can add more columns if you want
A very simple example of SelectColumns can be as below;
Select col example - subset =

SELECTCOLUMNS(
DimCustomer,
'Firstname',[FirstName],
'last name',[LastName]
)

The code above gives us a subset of the DimCustomer column with the two
columns of FirstName and LastName. but the two columns’ names can be
edited through the formula as you see.
Basics of SelectColumns DAX function in Power BI
In the example above, the column names only changed, but not the
expression. Expressions are merely the column value itself. However, you
can use an expression that changes the value like below;
select col example with calculation =
SELECTCOLUMNS(
DimCustomer,'Full Name',DimCustomer[FullName],
'Revenue',
CALCULATE(
SUM(FactInternetSales[SalesAmount]),
RELATEDTABLE(FactInternetSales)
)
)

The code above will generate a table with the same number of rows as the
DimCustomer, but only with the full name column and a new calculated
column of Revenue.

Using SelectColumns to add a new calculated column to the table in Power BI

SelectColumns Vs. AddColumns


One big difference between SelectColumns and AddColumns is that
AddColumns keep all the existing columns in the table and adds more
columns to that. Still, the SelectColumns start with no columns from the
table and builds a custom subset of columns or additional calculated
columns.
The difference of the SelectColumns with AddColumns is much more
visible when you look at a similar (but different) example of AddColumns
with a different result;
AddColumns Keeps the existing columns of the table
AddColumns keeps the existing columns of the table, But SelectColumns
start with no columns and adds to that.

Using SelectColumns in Measures as a


virtual table
Like many other tabular functions, the primary use case of SelectColumns
is when you create a virtual table inside a measure. If you have a function
that accepts a table as input, then SelectColumns can be used there.
When creating a virtual table, there are scenarios that you need a table with
only a subset of columns. For example, if you are using functions such
as UNION, INTERSET, or EXCEPT, you need two tables to have a similar
structure. SelectColumns is one of the functions that can help with that.
SelectColumn also is more efficient than AddColumns, because the size of
the table in memory is typically smaller. Here is a comparison of fetching a
random customer using the AddColumns method:
Checking the performance of AddColumns using DAX Studio
and an example of that using the SelectColumns method:
Checking the performance of SelectColumns using DAX Studio
The performance and also the size are much better using the
SelectColumns. This is understandable in the example above because the
DimCustomer table has 30 columns, and using AddColumns, the result
table will have 30+ columns. But the SelectColumns result has just two
columns output, which would take less memory.
This is not, of course, the case for all scenarios, and it depends. However, if
you are creating a virtual table, reducing the size of that table using
SelectColumns can have good performance impacts.

Summary
SelectColumns and AddColumns are very much the same. SelectColumns
is a tabular function that returns a table with a subset of columns (but the
same number of rows) from the original table. It may have additional
calculated columns in it. SelectColumns can be used instead of
AddColumns in many scenarios. And one of the most use-cases of this
function is when used inside another function to create a virtual table to
help the final calculation of a measure.
Chapter 45: TOPN DAX Function:
How it works in Power BI?
Comparison against the top group

TOPN is a function in DAX that allows you to select the top items from a
table based on an expression. In this chapter, I’ll explain how to use the
TopN function in DAX either to create a calculated table or to use it in a
measure to achieve analysis such as; comparison with the average amount
of the top group.

TOPN function in DAX


TOPN is a tabular function in DAX, and the table it returns is a subset of
the input table but only the top (or bottom) items of that table based on
evaluation of an expression. TOPN function can be used like this:
TOPN(<n_value>, <table>, <orderBy_expression>, [<order>[, <orderBy_expression>,
[<order>]]…])
n_value: The count of items you want to pick from the input
table's top or bottom.
table: the input table to get the subset of items from it
orderBy_expression: The expression used to order the table
items so that the top or bottom items be picked.
Order (optional): The selection should be from the top or
bottom of the table? Default is DESC which means TOP. If it
changes to ASC, it will act as the bottom.
As you can understand from the above, the TOPN function is used to get
the top items and the bottom items (based on the order parameter).

Some samples of TOPN


TOPN can be used as simple as below to give us the top 10 products based
on the sales.
TopN 1st example =
TOPN(
10,

DimProduct,
CALCULATE(sum(FactInternetSales[SalesAmount]))
)
Using TopN to create the top 10 products based on their sales in Power BI
The input table of the TOPN function can be any function that returns a
table as well. for example, the expression below is the top two product
colors based on the sales;
TopN 2nd example =
TOPN(
2,
VALUES(DimProduct[Color]),
CALCULATE(SUM(FactInternetSales[SalesAmount]))
)
Using virtual tables with TOPN
The example above doesn’t show the sales amount, so there isn’t an easy
way to test it. We can use a function such as Summarize to build a virtual
table with the Sales amount and then get the top items.
TopN 3rd example =
TOPN(
2,
SUMMARIZE(
DimProduct,
DimProduct[Color],
'Sales',
SUM(FactInternetSales[SalesAmount])
),

[Sales]
)

The whole Summarize section is used as the input table to the TOPN
function.
Get the top items with their sales amount using TOPN and Summarize

Bottom N
There are no function names as BottomN, but you can simply change the
order in the TOPN to ASC, and then you will get BottomN, as below;
Get bottom rows from a table using TOPN function in Power BI

When N is more than N!


TOPN usually should return a table with only N rows. However, in the case
of ties, it brings all ties. This means TopN of 10 might have more than ten
rows if there are two items with the same expression results in the top 10
list. Here is an example;
TOPN return all items with tie condition if they fit in the top list
To avoid this, you can change the expression in a way to avoid the tie. Or if
you want all the ties, then the result is what you expect anyway.

Using TOPN in Measures


TOPN can be used to create a calculated table, as you have seen in the
example above. However, similar to many other tabular functions, the most
powerful way of using it is when used in a measure. Using TOPN inside a
measure will give you the ability to dynamically top (or bottom) the list
based on selection criteria in the report.
Average Sales of the top items
For example, we want to calculate the average sales of the top colors as a
target. Our calculation can use TOPN to create a table with the top 3 items
in it as below:
var topGroup=
TOPN(
3,
SUMMARIZE(
ALL(DimProduct[Color]),

DimProduct[Color],
'Sales',
SUM(FactInternetSales[SalesAmount])
),
[Sales]
)

Then we can calculate the average from the outcome of that as below;
var averageOfTopGroup=AVERAGEX(topGroup,[Sales])

This average then can be used in a visual as a target. Here is the whole
expression:
TOPN used to dynamically calculate the average amount of top items in Power BI
This can be even used further to do conditional formatting with the help of
DAX with the measure below;
Back Color based on top group =
var topGroupValue=[Target High (average sales of top colors)]
var selectedColorSale=SUM(FactInternetSales[SalesAmount])
var SalesVsTarget=DIVIDE(selectedColorSale,topGroupValue)
return
SWITCH(
TRUE(),
SalesVsTarget>=1,'Green',
SalesVsTarget>=0.7,'Orange',
SalesVsTarget>=0.45,'Red',
'Black'
)

And the result is a table visual in both the target and the conditional
formatting calculated dynamically based on the average of the top 3 colors.

Summary
TOPN is a beneficial function when a calculation is required based on top
or bottom items in a list based on an expression. TOPN is a tabular
function, but if used in a measure, it gives a dynamic calculation possibility
which is helpful to create reports like above. TOPN can be used with the
ascending order to get the bottom rows as well. And TOPN will bring all
ties if they fit in the top items.
Chapter 46: Building a Virtual
Relationship in Power BI – Basics
of TREATAS DAX Function

TreatAs is an interesting function with multiple use cases in Power BI. I


thought it is good to explain it in a set of chapters. The first one here is
about the TreatAs function and how it can help build filters and a virtual
relationship between two tables. Let’s see how you can use this function.

Sample Data Model


The sample data model that I use here has three tables with no relationship
(Best practice for the below model would be to create the relationship.
However, I intentionally removed the relationship to explain the concept to
you through TreatAs function);
Filtering Values Using TREATAS
If I have a visual using EnglishEduction (from DimCustomer table) and
SalesAmount (from FactInternetSales table), then it would look like below;

The reason, of course, is not having the relationship between the two tables:
DimCustomer and FactInternetSales.
Now, to understand the TreatAs function, let’s see how the structure of
function usage is;
TreatAs(<expression>,<column 1>,<column 2>…)

The way that you should read TreatAs is this:


Treat <expression> As <column 1>,<column 2>….

Now, there are some rules in getting TreatAs working


Expression; the expression part of the function above is
a table expression. It means an expression that returns a
table. That means any function that returns a table can be used
here; Summarize, Values, Distinct, etc.
The order of Columns in the table expression should be the
same as the order of columns in <column 1>,<column 2>, etc.
Considering the two rules above, here is how you can use TreatAs to filter
the FactInternetSales table using the value of EnglishEduction in
DimCustomer;
SalesAmount using TreatAs =
CALCULATE(
SUM(FactInternetSales[SalesAmount]),
TREATAS(VALUES(DimCustomer[CustomerKey]),FactInternetSales[CustomerKey])
)

The result would be filtered by EnglishEduction, even though there is no


relationship between the two tables;

Now, let’s look at the TreatAs expression a bit more closely;

TREATAS(VALUES(DimCustomer[CustomerKey]),FactInternetSales[CustomerKey])
We connected the two tables using the CustomerKey. We are saying
that TREAT DimCustomer[CustomerKey] AS FactInternetSales[Custome
rKey]. It means to filter the FactInternetSales[CustomerKey] as of it is
DimCustomer[CustomerKey]. Or in other words; If
DimCustomer[CustomerKey] is filtered to show only CustomerKey XYZ,
then FactInternetSales[CustomerKey] would also be filtered to show only
CustomerKey XYZ. It is the same concept of having a relationship, but let’s
say a virtual relationship.

The VALUES part of the statement is because the EXPRESSION part


should be returning a table, not a column. VALUES is returning the unique
list of DimCustomer[CustomerKey] column. You can use other options
such as below too:
TREATAS(SELECTCOLUMNS(DimCustomer,'CustomerKey',DimCustomer[CustomerKey]),FactInte
rnetSales[CustomerKey])

The expression above will return the same result as Values in the visual
mentioned above.
but you cannot just say as below:
TREATAS(DimCustomer[CustomerKey],FactInternetSales[CustomerKey])

This will give you an error that you cannot use a column name in the
expression that expects a table expression.

Using Scalar Values and TREATAS


You will get the most value of TreatAs when you use a derived table using a
DAX function such as VALUES or any other function that gets the result of
a selection from a table. However, you can even use TREATAS with a
scalar table definition.
So it means, I can even have calculations like this:
Customers with High School Eduction =

CALCULATE(
COUNTROWS(DimCustomer),
TREATAS({'High School'},DimCustomer[EnglishEducation])
)

and the result will be the count of all customers with their EnglishEducation
as High School;
The {“High School”} is a single value table (single row and single column)
that filters the DimCustomer[EnglishEduction].

Virtual Relationship Using TREATAS


The first example that you saw used TREATAS to filter the SalesAmount in
FactInternetSales by the value selected from DimCustomer. You can use
this approach to create a virtual relationship. Let’s say you want to do a
role-playing-dimension and filter the OrderQuantity using OrderDate and
ShipDate both. I have explained how you can use the UseRelationship
method or cloning the date table as a role-playing dimension. Here is
another way of doing it using TreatAs.
I have a measure for Order Date;
qty by order date =
CALCULATE(
SUM(FactInternetSales[OrderQuantity]),
TREATAS(
VALUES(DimDate[DateKey]),
FactInternetSales[OrderDateKey]
))

and one for Ship Date;


qty by ship date =
CALCULATE(
SUM(FactInternetSales[OrderQuantity]),
TREATAS(
VALUES(DimDate[DateKey]),
FactInternetSales[ShipDateKey]
))

And as a result, with no relationship between the DimDate and


FactInternetSales, I get the calculations working perfectly fine;
Note that I am not saying that it is recommended to implement relationships
this way (for both the above examples, it is better to create an actual
relationship between tables rather than using TreatAS). I am showing you
the basics of using TreatAs and virtually building the relationship using this
function. In the next chapter, I’ll show examples of how you can filter based
on multiple fields.
Chapter 47: Creating Relationship
Based on Multiple Fields in Power
BI Using TREATAS DAX Function

TreatAs is helpful for filtering, and it doesn’t filter only based on one
column. It can filter based on as many columns as you want. One of the
challenges in Power BI relationships is creating a relationship based on
multiple fields. I have explained in a blog article a method you can use to
create a compound key and use that for the relationship. Another approach
is to use TreatAs. Let’s see how TreatAs can help in that scenario.

This is for Learning, Not


Recommendation
Although I explained in the previous chapter that you could create a virtual
relationship using TreatAs. In this chapter, I am describing how to create a
relationship based on multiple fields using TreatAs. These specific use
cases should not be considered as my recommendation. I explain these for
LEARNING. There are, of course, use cases to use TreatAs. However, this
chapter and the previous one just intend to explain how the function works,
so I stick to simple and easy-to-understand examples.

Sample Model
The sample model that I have includes two tables, one for Rating of Movies
and one for Sales of Movies. There is no relationship between the two
tables. The reason is that these two tables should be related based on two
fields: Title and Year in each table;

I always recommend scenarios like this to create a shared


dimension[https://radacad.com/creating-a-shared-dimension-in-power-bi-
using-power-query-basics-and-foundations-of-modeling] and use that for
filtering both tables, like what I
explained here[https://radacad.com/creating-a-shared-dimension-in-power-
bi-using-power-query-basics-and-foundations-of-modeling]. Another thing
that I recommend is to use compound
keys[https://radacad.com/relationship-in-power-bi-with-multiple-
columns] to create a relationship like what I
described here[https://radacad.com/relationship-in-power-bi-with-multiple-
columns]. But for this example, let’s put recommendations aside and talk
about the learning side of TreatAs function.
The purpose is to have a relationship like this:
TreatAs Function with Multiple Columns
I explained the basics of TreatAs function in the previous chapter, and you
learned that TreatAs require a table expression and a list of columns.
TreatAs(<expression>,<column 1>,<column 2>…)

The table expression should return precisely the same number of columns
that we refer to in TreatAs. I need the table expression to replace the two
columns Title and Rating from the Rating table, and then use the two
columns Title and Rating from the Sales table as parameters of TreatAs
columns.
Before using TreatAs, if I filter the Lifetime Gross field in the Sales table
by the Title and Year from the Rating table, I will get something like the
below;
Because there is no relationship to filter[https://radacad.com/back-to-basics-
power-bi-relationship-demystified] the Sales table, it shows the total value
regardless of the Title and Year. We need to say that the Title and Year
columns of the Rating table can filter the Title and Year columns of the
Sales table.
I can write a measure like below, but it won’t work;
The rating table includes both the Title and Year columns. However, it also
consists of a few other columns, as you see below:

So the Rating as a table expression returns four columns, but I just need
two; one for Title and one for Year.

Table Expression with the Same Column’s


count and Same Order of Columns
There are multiple ways you can write a DAX table expression that returns
only the two columns you need from the Rating table. SelectColumns is an
easy method for that;
SELECTCOLUMNS(
Rating,
'Title',Rating[Title],
'Year',Rating[Year])

The above expression will only return a table with two columns; Title and
Year. This table can be used as the table expression of TreatAs function like
below;
LifeTime Gross Using TreatAs =
CALCULATE(
SUM(Sales[Lifetime Gross]),

TREATAS(
SELECTCOLUMNS(
Rating,
'Title',Rating[Title],
'Year',Rating[Year]),
Sales[Title],
Sales[Year]
)
)

To understand how this works, I have explained it through the shape below;
The SelectColumns expression returns a table with only two columns: Title
and Year. Then the values of this table are used to filter the values of
subsequent columns of Title and Year from the Sales table. The order of
columns should be the same. You cannot have a table returning Title, Year,
and then filter the Year, Title with it. You probably won’t get any results
with that combination. The name of the columns is not important. The
values in each column are.
The result of the expression below is as below:

Even though there is no relationship between the two tables, using TreatAs,
we created that relationship for this measure using the two columns; Title
and Year. You see some blank values in the result. That is because not every
movie that is in the Rating table exists in the Sales table.
So I sum up the learning of this chapter for you:
The table expression should return a table with the same
number of columns with the same order of the columns used
in the list of columns for the TREATAS function.

Last but not least, this chapter was explaining the functionality of
TREATAS for learning. It is not recommended, though, to create a
relationship like this; I always recommend scenarios like this to create a
shared dimension[https://radacad.com/creating-a-shared-dimension-in-
power-bi-using-power-query-basics-and-foundations-of-modeling] and use
that for filtering both tables, like what I
explained here[https://radacad.com/creating-a-shared-dimension-in-power-
bi-using-power-query-basics-and-foundations-of-modeling]. Another thing
that I recommend is to use compound
keys[https://radacad.com/relationship-in-power-bi-with-multiple-
columns] to create a relationship like what I
described here[https://radacad.com/relationship-in-power-bi-with-multiple-
columns].
Chapter 48: Age Banding in Power
BI Using TREATAS DAX Function
– Relationship Based on Between

One of the most common types of banding or binning is banding based on a


range. Let’s say, for example, you want to have a group of customers based
on their age group. The age group banding can be created in Power Query
at the data transformation stage. It can be created using the Grouping and
Binning option in Power BI[https://radacad.com/grouping-and-binning-
step-towards-better-data-visualization], or it can be even created using
DAX measures. If you use a DAX measure for the banding, TREATAS can
help implement it. In this chapter, I’ll explain how it works.

If you are New to TREATAS


If you haven’t used TREATAS before and are new to using this function, I
recommend reading the two previous chapters explaining how TREATAS
works.

Sample Model
I am using a straightforward data model in this example. The table below is
what I use as the Sample Data;
Sample Data =
DATATABLE(
'First Name',STRING,

'Last Name',STRING,
'Age',INTEGER,
{
{'Reza','Rad',40},
{'Mick','Peterson',34},
{'Joe','White',23}
}
)

The goal is to have an age group banding for customers and get a count of
customers in each group. Something similar to this:
Other Methods for Banding
You can use Power Query with a conditional column to create banding or
use the grouping and binning option in Power
BI[https://radacad.com/grouping-and-binning-step-towards-better-data-
visualization] to achieve the same. Here, in this chapter, however, I will
explain how that is possible through a measure using the TREATAS
function.

Age Band Table


As we need the banding to be the axis of the chart, we require that as a
field, You can create an age band table using What-If parameters, using the
GenerateSeries function, or simply using an expression like this:
Age Band =
DATATABLE(
'Age Band',INTEGER,
{
{10},{20},{30},{40}
}
)

here is how the Age Band table looks like:

When you see ten as the band up there, it means from 1 to 10. When you
see 20, it means from 11 to 20 and so on.
This table shouldn’t have a relationship with the Sample Data table because
if you create the relationship, it would only filter data for the top value of
each band. So the tables remain unrelated, like a standard way of using
a What-if parameter table.

DAX Measure using TREATAS


Now, using a measure like below, we can get the count of people in each
band;
Count of Rows in Each Band =
var _currAgeBand=SELECTEDVALUE('Age Band'[Age Band])
var _currAgeList=GENERATESERIES(
_currAgeBand-9,_currAgeBand,1)
return
CALCULATE(
COUNTROWS('Sample Data'),
TREATAS(_currAgeList,'Sample Data'[Age])
)

The expression can be split into multiple sections. First is the variable that
fetches the current age band (the age band in the visualization’s filter
context);
var _currAgeBand=SELECTEDVALUE('Age Band'[Age Band])

Then the next variable is a list (table) of values from the selected age band
minus nine to the value itself, increasing one at a time. For example, if the
age band value is 40, this list would be from 31 to 40: 31, 32, 33, …., 40.
var _currAgeList=GENERATESERIES(
_currAgeBand-9,_currAgeBand,1)

Now that we have a list of possible age values for this band, we can use that
to filter the Sample Data table using TREATAS;
CALCULATE(
COUNTROWS('Sample Data'),
TREATAS(_currAgeList,'Sample Data'[Age])
)

Altogether, this works like a scenario that you have created a relationship
between the Age Band table and the Sample Data but on a BETWEEN
condition, not an exact equal condition.
This example shows a fascinating use case for TREATAS, creating a
relationship based on not-equal criteria. Relationships in Power BI are
based on equality of values. You cannot create a relationship that says this
value should be less than or equal, or between, or anything like that of the
other value in the other table. However, using TREATAS combined with
other functions, you can do that. I’ll write about this design pattern
separately later in detail.

Age Bands with Start and End


If we step beyond the introductory example, we can even create a bit more
advanced banding. One of the limitations of grouping and binning in Power
BI is that bins should be all of equal size. For example, all age bands should
be of 10 years, or all five years. You cannot say some are smaller than
others. Using your own Age Band table, however, you can define what you
want. Here is another detailed Age Band table;
Age Band Detailed =
DATATABLE(
'Age Band',STRING,

'Sort Order',INTEGER,
'Start',INTEGER,
'End',INTEGER,
{
{'1-10',1,1,10},
{'11-20',2,11,20},
{'21-25',3,21,25},
{'26-30',4,26,30},
{'31-35',5,31,35},
{'36-40',6,36,40}
}

and the table looks like this:


As you see, I have bands that only cover five years (31-35) and bands
covering ten years (11-20).

DAX Measure For Custom Bands


The DAX calculation is very similar to the previous one, the only difference
is that we do not need to go nine years back, we have the start and end, and
can generate the period using those;
Count of Rows in Each Band - Detailed =
var _currAgeBandStart=SELECTEDVALUE('Age Band Detailed'[Start])
var _currAgeBandEnd=SELECTEDVALUE('Age Band Detailed'[End])
var _currAgeList=GENERATESERIES(
_currAgeBandStart,_currAgeBandEnd,1)
return
CALCULATE(
COUNTROWS('Sample Data'),
TREATAS(_currAgeList,'Sample Data'[Age])
)

The result is as below;


Creating the Relationship Based on
Between
Age banding and grouping here was just an example to show the main
pattern. The pattern is whenever you want to create the relationship
between two tables based on a not equal condition, but it is between, how
you can do it.

The trick to making this pattern of creating a relationship


based on between criteria is to use a function such as
GenerateSeries to build a list of possible values between
the two ends of each band, and then use it in TREATAS (or
any other filter functions) to filter the value in the other
table. That is what you see highlighted in the expression
above.
Chapter 49: Aggregated Table in
Power BI with Extra Options –
Summarize Function in DAX

This chapter will explain how you can use Summarize function for
aggregation and grouping of a data table. Summarize function gives you
more control over how to create your aggregated table with some extra
functions. Let’s see how it works. Creating aggregated tables using DAX
functions is particularly very useful when creating virtual tables inside
DAX measures.

Sample Dataset
My sample dataset table is DimCustomer as below;

Summarize Function
Summarize is a DAX function that gives you an aggregated result from a
table. This is how you can use Summarize function:
Summarize(<table>,<grouping column>,[<name>,<expression>])

Table; a DAX expression that returns a table, or just one of the


tables in your dataset
grouping column; the name of the column you want to use for
grouping
name; the name of the new aggregated column
expression; the expression to generate the aggregated column.
Summarize function returns a table as the output. The definition of
Summarize function as above looks very similar to GroupBy. However,
there are some differences. Let’s go through some examples, and you’ll see
examples of that.

Summarize: Just Grouping


The simplest way of using Summarize function is using it for only
grouping, which will give us the unique list of values of a grouping column
(similar to what you can achieve with DISTINCT, or VALUES functions);
Summarize - Just Group =
SUMMARIZE(
DimCustomer,
DimCustomer[EnglishEducation])

The expression generates the below result;

Summarize With Aggregations


Now, let’s take it one step further, and use it for aggregation. And remember
that you can also have more than one grouping column;
Summarize - with aggregation =
SUMMARIZE(
DimCustomer,
DimCustomer[EnglishEducation],
DimCustomer[Gender],
'Row Count',
COUNT(DimCustomer[CustomerKey]))

In the expression above, the grouping columns are EnglishEducation and


Gender. And the aggregation is the count of customers in each group. The
result is the count of customers for each EnglishEducation and Gender as
below;

You can have more than one aggregation if you want to. Just add the name
of each column and the aggregation expression.

Summarize with RollUp: Totals in the


Table
So far, what you have seen was the usage of Summarize simply with only
grouping columns and aggregations. That usage is similar to using
the GroupBy function. You can, however, using Summarize to add more
options to your output table. This can be in the form of totals. Let’s say you
are also interested in seeing the totals of categories and all other results we
have had so far. This can be achieved using a RollUp function.
Summarize - with Rollup =
SUMMARIZE(
DimCustomer,
ROLLUP(DimCustomer[Gender]),
'Row Count',
COUNT(DimCustomer[CustomerKey]))

The above expression, not only create the aggregated result per each
Gender, but it also will have one extra ROW in the table for the totals (all
genders);

The RollUp comes in the place that the grouping column should be, and it
means the grouped results, PLUS the total.
What if Two or More RollUps
Like a matrix way of grouping, if you have more columns inside the
RollUp, Rolling up values (or total calculation, let’s say) goes through them
one by one in the order in which they are written inside the RollUp
function.
Summarize - with Two Rollups =
SUMMARIZE(
DimCustomer,
ROLLUP(DimCustomer[Gender],DimCustomer[EnglishEducation]),
'Row Count',

COUNT(DimCustomer[CustomerKey]))

This means that after doing all the grouping, roll up on EnglishEduction
first, but with the grouping on Gender (highlighted green below with the
number 1), and then roll up on Gender (highlighted yellow below with the
number 2);
Changing the order of using columns inside RollUp will change the result
of roll-up columns.

RollUpGroup
RollUpGroup can be used similarly to RollUp for bringing the totals and
sub-totals into the aggregated results. If we replace the RollUp with
RollUpGroup in the previous expression, we get precisely the same result;
Summarize - with Two RollupGroups =
SUMMARIZE(
DimCustomer,
ROLLUPGROUP(
DimCustomer[Gender],
DimCustomer[EnglishEducation]
),
'Row Count',

COUNT(DimCustomer[CustomerKey]))

So, you can use either RollUp or RollUp Group to get totals and subtotals.
Preventing Subtotals: Combining RollUp
and RollUpGroup
One of the main usages of RollUpGroup, is to combine it with RollUp and
use it as a parameter inside the RollUp function. This will lead to the
removal of subtotal values and only showing the totals.
In the expression below, you can see that the RollUpGroup is used inside
the RollUp function;
Summarize - with Rollup and Group =
SUMMARIZE(
DimCustomer,
ROLLUP(ROLLUPGROUP(DimCustomer[Gender],DimCustomer[EnglishEducation])),
'Row Count',
COUNT(DimCustomer[CustomerKey]))

The result only shows one total Row;

Checking if the Row is a SubTotal Row?


IsSubTotal
Sometimes, you need to check in the result set and see if this is a subtotal
row or not. Let’s say you want to calculate a percentage, and you want to do
that only for rows that are not subtotal. There is a function named
IsSubTotal, which returns True or False, saying that is this row a subtotal
row or not.
The expression below has three columns to check is this subtotal of Gender,
Eduction or combination of both;
Summarize - with IsSubtotal =
SUMMARIZE(
DimCustomer,
ROLLUP(DimCustomer[Gender],DimCustomer[EnglishEducation]),
'Row Count',
COUNT(DimCustomer[CustomerKey]),
'Gender Subtotal',ISSUBTOTAL(DimCustomer[Gender]),
'Education Subtotal',ISSUBTOTAL(DimCustomer[EnglishEducation]),

'Total',ISSUBTOTAL(DimCustomer[EnglishEducation])&&ISSUBTOTAL(DimCustomer[Gender]))

The result would have three columns showing where is the subtotal and
where not

Each IsSubtotal used inside a new column, and if the result row is a subtotal
on that field, then it returns true for that row.
As an example, If you want to calculate the percentage of the count of
customers against the total for every row, but not for subtotal, you can do
this:
07 Summarize - with IsSubtotal for % calc =
var _allCustomers=COUNTX(DimCustomer,DimCustomer[CustomerKey])
return
SUMMARIZE(
DimCustomer,
ROLLUP(DimCustomer[Gender],DimCustomer[EnglishEducation]),
'Row Count',
COUNT(DimCustomer[CustomerKey]),
'%',if(

NOT(ISSUBTOTAL(DimCustomer[EnglishEducation])||ISSUBTOTAL(DimCustomer[Gender]))
,DIVIDE(COUNT(DimCustomer[CustomerKey]),_allCustomers)
),
'Gender Subtotal',ISSUBTOTAL(DimCustomer[Gender]),
'Education Subtotal',ISSUBTOTAL(DimCustomer[EnglishEducation]),

'Total',ISSUBTOTAL(DimCustomer[EnglishEducation])&&ISSUBTOTAL(DimCustomer[Gender]))

and the result will be like the below:


Summary
Summarize is another DAX function that can be used to create an
aggregated table in Power BI. This function can have advanced features of
controlling totals and subtotal with some extra options. You have seen some
examples of Summarize for grouping, aggregation, RollUp, RollUpGroup,
and IsSubTotal functions. The Summarize function can be used to create a
virtual table or a calculated table in Power BI. However, the first one is the
one that is used a lot inside measures for dynamic calculation’s purposes.
Chapter 50: Aggregated Table in
Power BI – Using GroupBy
Function in DAX

There are many different ways you can create aggregations in Power BI.
You can do it in the source (using the database t-SQL language) or using
Group By operation in Power Query. You can also do it in DAX using some
functions. One of the functions that can be used for grouping and
aggregation is Group By. This chapter is about how to use Group By in
DAX. Creating aggregation using DAX is a very useful skill because you
can use it to create virtual tables in your measures and have better dynamic
calculations in Power BI.

Sample Data
My sample dataset table is DimCustomer as below;
GroupBy Function
GroupBy DAX function can be used as below:
GROUPBY( <table>, <grouping column1>, [<output aggregation column name>, <expression for
aggregation column>]…)

The Table can be a table in your dataset or any virtual table


(means any function that returns a table).
Grouping column1: the column that you want the resultset to
be grouped by that column. This is an existing column in the
table above.
Name: the name that you give to the new column created.
Expression: the expression that is used for the new column
created.
You can have more than one grouping column.
Just Grouping
As an example, a primary usage of GroupBy is to create a list of unique
EnglishEducation values from the DimCustomer table with the below
expression:
GroupBy - Just Group = GROUPBY(
DimCustomer,DimCustomer[EnglishEducation])
This is used to create a calculated table, and here you can see the result:

In the above example, the table is DimCustomer, and the Grouping happens
on the EnglishEducation column of that table. The result is the grouped list
of EnglishEducation, which is the same as DISTINCT or VALUES
functions. If you want a distinct list, you might use one of the other two
functions rather than GroupBy. Using the GroupBy function usually comes
with a new column which is the aggregated result.

Grouping and Aggregation:


CurrentGroup
If you want to do grouping and aggregation using GroupBy, you should use
an important function: CurrentGroup. Let’s say you want to calculate the
count of customers within each group of EnglishEducation. You might think
of an expression like this:
The Row Count column is supposed to show the count of customers for
each EnglishEduction group. However, if you use it as the above
expression, you will get this error:
Function ‘GROUPBY’ scalar expressions have to be Aggregation functions
over CurrentGroup(). The expression of each Aggregation has to be either a
constant or directly reference the columns in CurrentGroup().
CurrentGroup
CurrentGroup is a DAX function that comes with the usage of GROUPBY.
CurrentGroup means the subset of the main table, which can be used for
any aggregation. I used the below sample to show you what the
CurrentGroup looks like. However, you cannot see that visually. This
happens behind the scene.

The screenshot above is creating using Power Query Editor. I used it to


show you what the Current Group looks like, so don’t look for a visual way
of looking at CurrentGroup in DAX. As you see in the screenshot above,
the CurrentGroup, when our filter context is High School, is the sub-table
of DimCustomer with all of the columns, but filtered only for High School.
Now, using CurrenGroup, you can write the expression as below;
GroupBy - with aggregation = GROUPBY(
DimCustomer,DimCustomer[EnglishEducation],
'Row Count',

COUNTX(
CURRENTGROUP(),
DimCustomer[CustomerKey]
)
)

The CountX expression is counting rows from the CurrentGroup function.

The CurrentGroup can be used in other iterator functions such as SUMX,


AverageX, etc.
Some Restrictions of GroupBy
You cannot use a Calculate function in the expression section of GroupBy.
Any aggregation should be done using the CurrentGroup function.

The table can be an expression too


Using GroupBy (and many other functions), you can use a real dataset table
as the input. You can use another function that produces a table (table
expression). The below example shows a scenario what we create a column
in the DimCustomer table for the Revenue first, and then use that for
grouping in the next step;
Sales in the above expression is a measure with the expression of
Sum(FactInternetSales[SalesAmount]).

Remember the Power of Virtual Tables


If you want to use GroupBy to create an aggregated calculated table in
Power BI, you can do it. However, there might be a better way to do it;
using GroupBy in Power Query or the data source. The main power of
using GROUPBY or other DAX grouping functions is to use them as a
virtual table, an aggregated table created on the fly inside a measure
definition. Using a virtual table makes your DAX measure even more
powerful. However, you need to be aware that with the power comes other
costs too. Sometimes virtual tables might cause performance impact.
Chapter 51: Combining Tables in
Power BI: Union, Except, and
Intersect in DAX

Power Query is often the engine used for combining data tables, especially
using Merge or Append[https://radacad.com/append-vs-merge-in-power-bi-
and-power-query]. However, sometimes, you might need to do that
operation in DAX. An example is when you want to create that combination
only virtually as part of a measure calculation that evaluates dynamically.
This chapter will explain three DAX functions and their meanings: Union,
Except, and Intersect.

Sample Data
I have two really simple data tables, each with one column: Column 1;
sample data tables
For the operations below, each table can have more than one column.
However, I keep it simple to understand.

Union
If you want to have all the data rows of the two tables appended to each
other, you can use the UNION function in DAX. This function simply gets
the two input tables and returns the appended result.
UNION(Table1,Table2)

The Union function is tabular and cannot be used directly in a measure. It


has to be used either in a calculated table or inside another function.
Union function in DAX
Union function does not remove duplicate values that might happen after
the operation. You can use Distinct or Values functions for that.

Intersect
Intersect only returns the rows that exist in both tables. All of those rows
that exist in only one of the tables will be removed from the resultset. This
is how you can use Intersect;
INTERSECT(Table1,Table2)

As you can see, the syntax that INTERSECT and UNION are used are
precisely the same. The same rule applies to EXCEPT as well. For these
three functions, you just need two input parameters; the two tables.
Intersect function in DAX

Except
For the UNION and INTERSECT, the order of passing the tables to the
function doesn’t matter (the only impact would be the final order of items in
the result set). However, for the Except, the order of tables is important.
If you want all rows from table1 that does not exist in table2, then you can
write as below;
EXCEPT(Table1,Table2)

The result would be all rows that only exist in table1.


Except function in DAX
If you change the order of tables, then you get a different result;
EXCEPT(Table2,Table1)

This would be all rows that exist in table2 only.

Except function in DAX

Important considerations
In all of the functions above, you need two tables to have the same
structure. The exact structure means the same number of columns. The
matching is based on the position of the column in the table.
If you use the techniques above to create a calculated table, I strongly
recommend you look at Append and Merge[https://radacad.com/append-vs-
merge-in-power-bi-and-power-query] transformations in Power Query.
Often they can be a much better option if the purpose of this work is
transformation. Only use it in DAX if you are targeting a dynamic combine
approach.
Chapter 52: Creating a List of
Numbers or Dates in Power BI
using GenerateSeries Function in
DAX

If you ever need to create a list of numbers (either decimal or whole number)
or a list of dates and times, a straightforward and useful function in DAX
helps. GenerateSeries is a simple function to use to create a list. In this
chapter, I’ll explain how you can use this function.

Table Generators
There are a set of functions in DAX which generates a table. Some of these
functions are from the form of table constructors. I have written about
the Table Constructor in DAX and also the DataTable() function.
There is another set of functions to generate a table. I have written
about Calendar() and CalendarAuto() functions and explained how they
could create a table with a list of dates. This chapter describes
the GenerateSeries() function in DAX and how you can create a table with it.

GenerateSeries
GenerateSeries is a function in DAX that generates a list of values. The list
starts from a Start value and ends at an End value. You can also specify an
increment. However, the increment value is optional, and if you don’t set
that value, the default increment would be 1.
GenerateSeries(<start value>,<end value>,[increment value])

Sample Usage: Creating List of Numbers


GenerateSeries is a simple function to use. You can easily use it with the
expression below:
Sample Table = GENERATESERIES(1,10)
The result would be a table with values from one to ten, incrementing one at
a time (the default increment value is one).
Your numbers can be even negative as below;
Sample Table = GENERATESERIES(-3,3)

Changing the Increment Value


You can also change the increment value to whatever you want.
Sample Table = GENERATESERIES(0,10,2)
The start and end value or/and the increment value can also be decimal
values.
Sample Table = GENERATESERIES(1.0,3.0,0.4)

You might, however, need to set the number of decimal place characters to
the correct value to see the effect.

List of Dates
GenerateSeries is not just for numeric values. It also works for date values.
Here is an example:
Sample Table = GENERATESERIES(

DATE(2019,10,1),
DATE(2019,10,15)
)
The default increment is one value, which for the data type of DateTime
means one day. You can, however, change it to weekly or any other
durations with changing the increment:
Sample Table = GENERATESERIES(
DATE(2019,10,1),
DATE(2019,10,15),
7
)
If you are looking for other ways of creating a list of dates, check out the
chapter about Calendar() and CalnedarAuto() functions in DAX.

List of Times
You can also generate a list of Times using the same function;
Table = GENERATESERIES(
Time(1,0,0),
TIME(2,0,0),
1/24/60/60)

Change the increment


However, you need to set the increment for the time value because the
default is one day, which won’t affect the time over 24 hours! If you want to
get to other time portions, you can follow this approach:
1: means a day: 24 hours
1/24: means one hour
1/24/60: means one minute
1/24/2: means a half hour
1/24/60/60: means one second

And you can build all types of other combinations. Below is a table of times,
adding one second at each row;

List of Currency Values


Table = GENERATESERIES(
CURRENCY(100.30),
CURRENCY(110.1),
CURRENCY(0.5)
)
GenerateSeries is used when you create a
What If Parameter in Power BI
When you create a What If Parameter in Power BI, behind the scene, the
GenerateSeries function is used:

The What If Parameter is a list of values in DAX which is generated using


the GenerateSeries function.

Summary
In summary, if you want to create a list of values in Power BI using DAX,
GenerateSeries is an excellent function to do that. It works not only with
numeric values but also with date and time values.
Chapter 53: Create a Table with A
to Z Character Values in Power BI
Using DAX
I have explained that you can use the GenerateSeries function in DAX to
create a list of numbers, dates or times, or even currency values. However,
sometimes you might need to create a list of text values, such as alphabet,
from “a” to “z” lowercase or uppercase. The good news is that you can also
do that with GenerateSeries, and a bit of a trick. Let’s see how it works.
GenerateSeries for Numbers
I explained that you could create a calculated table in Power BI using DAX
expression such as below and get the result as a one-column table;
Sample Table = GENERATESERIES(1,10)

You can use GenerateSeries to create a list of dates, times, and currency
values too.

UNICODE: Returns the Code of the


Character
You cannot use GenerateSeries to create a list of characters, unfortunately.
An expression like below would give you an error; “The arguments in
GenerateSeries function must be of a numeric or date/time type”.

However, the trick is that every character has a numeric code assign to it in
the Unicode world. The UNICODE function will give you the code of that
character:
for example, an expression like below:
Code of the character = UNICODE("a")

as a measure, it will return 97.

The 97 is the numeric code for character “a”.


Another good news is that these characters generate codes in the same
order. So character “b” is code 98.

List of Codes
So, now you can simply create a table like this:
Codes = GENERATESERIES(
UNICODE("a"),
UNICODE("z")
)

and you will have the list of all codes in one place:
UNICHAR: Returns the Character of the
Code
The point, however, is not to have the list of codes but to have the list of
characters. You can use the UNICHAR function in DAX to return the
character related to the code.
For example, the expression below;
Character of the code = UNICHAR(97)

As a measure, returns the character “a”;

Convert the List of Codes to the List of


Characters
Now, the last step is to convert the list of Codes to a list of characters,
which can be done using a SelectColumns function and UNICHAR
function combined as below;
Alphabet =
SELECTCOLUMNS(

GENERATESERIES(UNICODE("a"),UNICODE("z")),
"Character",
UNICHAR([Value])
)

and here is the result, which is the list from “a” to “z”;
All Characters
You can modify the expression a bit and get a list of all primary Latin
characters like this:
Alphabet =
SELECTCOLUMNS(
GENERATESERIES(UNICODE("a"),UNICODE("z")),
"Character",
UNICHAR([Value])
)

Or even more characters. Use the list of characters


mentioned here[https://en.wikipedia.org/wiki/List_of_Unicode_characters]
as a reference.
Part 8: Text functions
Chapter 54: Substring in DAX:
How to get Part of String Field in
Power BI Using DAX Expression

Substring is one of the most common functions in many languages. There is


a MID function in DAX that works as a substring. However, learning
alternative ways will teach you some other text-related functions. There is a
very simple way of doing it, which I will explain in this chapter. Substring
means getting part of a string, for example, from “Reza Rad”, if I want to
get the start starting from index 2, for 4 characters, it should return “za R”.
Considering that the first character is index 0. Let’s see how this is possible.

Sample Data
I have a sample customer table as below;

Substring
Substring means saying from character indexed N, extract M characters:
Substring (N, M)
This can be implemented in DAX in different ways. This is one of the
methods:
Substring = LEFT(
RIGHT(
DimCustomer[EmailAddress],
LEN(DimCustomer[EmailAddress])-1
),
3)

This added as a column to this table,


This will produce characters starting from index 1 for the length of 3.

1, in the expression above, is the starting index. If you want to start from
the beginning of the text, use zero here.
3, in the expression above, is the length of the output from the starting
index.
here is another example:
There is an easier way to do substring too, using MID function;
MID = MID(DimCustomer[EmailAddress],5,7)

Using the MID function, you just specify the starting index and the length
of characters to extract, similar to substring in many other languages.

Reverse Substring
Sometimes you want substring to start from the end of the text. For
example, ReverseSubString (N, M) means to start from N, which is the
index from the right end of the string, and extract M characters. For
example, “Reza Rad”, with ReverseSubstring(3,2), means “Ra”. You can
implement the Reverse substring as below:
Reverse Substring = LEFT(
RIGHT(DimCustomer[FullName],3)
,2)

the result is:

This method is usually more useful when the value you want to extract is
closer to the end of the string rather than the start.
Chapter 55: Find a Text Term in a
Field in Power BI Using DAX
Functions

In Power BI, there are multiple ways of searching for a text term inside a
text field. You can use Power Query for doing this operation or calculations
in DAX. In this chapter, I’ll explain some functions in DAX that you can
use to do this calculation. Most of these functions can be used inside a
measure for dynamic calculation. In this chapter, you will learn about a few
DAX functions that deal with searching a text term in a text field.

Sample Data
I am using the DimCustomer table from the AdventureWorks excel file, and
only two columns of that, which are CustomerKey and FullName;
FIND
Find is a DAX function that searches for a term inside a text field and
returns the starting position of that item (position index starts from one).
The way that you can use this function is like below:
FIND(<text term to search for>,<the column you are searching into>,[<starting index for search>],
[<result if the text term is not found>])

Here is an example of using this function:


FIND = FIND("A",DimCustomer[FullName],,-1)

The above expression searches for the term “A” inside the column
FullName of DimCustomer table, starting from the very first of the value in
that column’s cell, and if it can’t find the value, it returns -1.
The expression above is defined as a column, so as a result, it will run for
every row (however, you can use the FIND function in a measure if you
want). If it cannot find the value, it returns -1, and if it can find it, it returns
the index of that in the text (it returns the first index of that term if it
appears multiple times). For example, The customer's full name “Janet
Alvarez” contains the character “A” as the seventh character in the text, so
the return is 7. However, “Ruben Torres” doesn’t contain “A”, and it returns
-1.
FIND Is Case Sensitive
You might have wondered why the result of the above expression for “Jon
Yang” is still -1, although we have character “a” in there. The reason is that
FIND is a case-sensitive function. There is a difference between the above
expression if you use “A” or “a” in the FIND;

Another thing is that although the last parameter of the FIND is optional, if
you don’t pass a value to it, it returns an ERROR.

SEARCH
Search is very similar to FIND. The only difference is that Search is NOT
case sensitive. There is no difference between “A” or “a” when you use
the Search function.
Search = SEARCH("A",DimCustomer[FullName],,-1)

The example below is using the Search function in a calculated column;


Tailoring FIND not to be Cast Sensitive
You can easily change FIND or SEARCH to return precisely the same
result too. Meaning that you can make FIND not case sensitive or SEARCH
case sensitive with the help of other functions. Here is an example of how
you can make FIND not case sensitive:

The above expression uses UPPER to make the FullName’s value all
uppercase, and then compare it with “A”, or you can do lowercase, and then
compare it with “a”.

ContainsString
FIND and SEARCH functions are returning the starting index of the search
term. However, the ContainsString function returns a boolean result that is
that term found in the text or not. The result of this function is true or false.
ContainsString just need to parameters;
ContainsString(<the column you are searching into>,<text term to search for>)

Here is the result of this function used in an example:

ContainsString is not case sensitive, and it returns true for any of those
values that the Search function returns a value not equal to -1 in our
example.

ContainsStringExact
There is a case-sensitive version of the ContainsString, called
ContainsStringExact. The function can be used similar to the previous one;

Exact
Exact is not a function to search through a text. This is a function to check
the equality of value with a text. The two texts should be exactly the same.
This function is case-sensitive. Exact, get two text values and check if
they are the same or not, the result is a true or false value;
Exact(<text 1>,<text 2>)

Using the Exact, you can write an expression like below;


Other Functions
Other functions work with text search, such as Contains. Note that the term
lookup can also be done using Power Query, and if the purpose is to do pre-
calculation, then it is better to do that in Power Query as a transformation.
However, if the scenario needs to be dynamic, then using the functions
above in a measure helps.

All in One
Here is a summary of these functions;
Chapter 56: Search in Power BI
Table Visual Using a Slicer For
Contains Character Criteria
If you have a lot of text in a table visual in Power BI and want to search to
find all texts with a specific character in them, I have a solution for you.
You can have an alphabet slicer and use it to filter the table. The trick is to
combine it with a measure and use it as a parameter table. Let’s see how the
solution works.
The Challenge
I have a table for all customers, showing them all in a table visual in Power
BI. However, there are many customers on the list, let’s say 18K+. If I want
to search for all customers who have “q” in the name, then I need to either
scan the table myself, Or use a slicer with a search box, and search for
character “q”, and then select all the names with “q” one by one! Something
like below is tedious!

This is not good. Now let’s see what can be done.

Slicer with Contains Criteria Output


This is the sample output I am looking for; I select the character in the
slicer, and then the table just gets filtered and shows me all names with that
character used in it:

This is great, isn’t it? Now that you can see what is expected and can be
done let’s see how you can do that.
Alphabet Table: Parameter Table
I started this by creating a parameter table for the Alphabet. The parameter
table is a table that can be used to filter the result of visualizations, but not
through the relationship, through some DAX measures. You can usually
create a parameter table using What-If parameters in DAX if your
parameter table consists of numeric values. However, in this case, our table
includes a list of characters, so we need to create that ourselves using a
DAX expression:
Alphabet =
SELECTCOLUMNS(
GENERATESERIES(UNICODE('a'),UNICODE('z')),
'Character',
UNICHAR([Value])
)

and this will give me a table with all the characters:


Make sure this table has NO relationship to your Customer table;
DAX Measure to Check Contains
Now the next step is to create a DAX measure that checks if the FullName
column of the Customer table contains the selected character or not? The
below simple measure can do that:
Exists = SEARCH(
SELECTEDVALUE(Alphabet[Character]),

SELECTEDVALUE(Customer[FullName]),
,-1)

I have used the Search DAX function here. The search function will return
the character index in the text if it finds the value (starting from one), and as
the last parameter I mentioned, “-1” will return -1 if it cannot find the
character in the text. You can use FIND or other functions in DAX to
achieve similar results.

Visual Filtering
Now you can create visualization like below, the slicer value is coming
from the Alphabet table, and the table visual is from the Customer table;
In the visual level filter of the table visual, Add the Exists measure (the
measure we have created in the previous step), and set the filter to “is
greater than or equal to” and type “1” in the text box, and apply filter.
That’s it. This will give you the result below:
I’m sure soon, the Slicer in Power BI will somehow have a feature like this,
but this is a solution you can implement and use until then.
Chapter 57: Search for All the
Texts in Power BI Table Visual
with the First Three Characters
Selected in the Slicer

What if we want to search for the first few characters of a text using a
slicer? that means selecting the first character, seeing all the possible second
characters, selecting from that list, and then all possible third characters.
And the table visual shows all text values with the result of all these
selections. So, the result is this chapter. I’ll show you how this is possible;

Search all texts that Contain a Character


If you want to learn about the first step of this operation, read the previous
chapter that I explained how you could achieve below:

The Desired Outcome


You might have seen some ticketing systems for trains where the user type
in character, and the machine shows all possible train station destinations
based on that first world, then the user can type the 2nd character, and 3rd,
etc. This is what you can do in Power BI too, Here is an example of what is
expected:

Three Parameter tables


For this implementation, you need to have three Alphabet tables. The first
table can be produced with the expression below;
Alphabet =
SELECTCOLUMNS(
GENERATESERIES(UNICODE('a'),UNICODE('z')),
'Character',
UNICHAR([Value])
)
The second and third tables can be created just as role-playing-
dimension copies:
2nd Char = ALL(Alphabet)

The model looks like below


There is no relationship between these tables.

Three Slicers
Use the three tables respectively in three slicers as below;
DAX Measures
There is a bit of measure work involved in this solution. A measure that can
check the first, the second, and the third characters, and also measures to
filter the visuals. Below is the list of measures one by one:
First Character Matched
This measure checks if the first slicer's value exists as the first character in
the FullName column of the customer table. If the result of this measure is
1, then it means a match.
First character matched = SEARCH(

SELECTEDVALUE(Alphabet[Character]),
SELECTEDVALUE(Customer[FullName]),
1,
-1)
The second Character Matched
This measure checks if the second slicer's value exists as the second
character in the FullName column of the customer table. If the result of this
measure is 2, then it means a match.
Second character matched =
var _selectedChar=SELECTEDVALUE('2nd Char'[Character])
return
if(ISBLANK(_selectedChar),2,
SEARCH(
_selectedChar,
SELECTEDVALUE(Customer[FullName]),
2,
-1)
)

The third Character Matched


This measure checks if the third slicer's value exists as the third character in
the FullName column of the customer table. If the result of this measure is
3, then it means a match.
Third character matched =
var _selectedChar=SELECTEDVALUE('3rd Char'[Character])
return
if(ISBLANK(_selectedChar),3,

SEARCH(
_selectedChar,
SELECTEDVALUE(Customer[FullName]),
3,
-1)
)
Now using the three measures above, we create some more measures for
filtering as below;
Second Characters
This measure filters the second character slicer with all possible options
based on the first character slicer selection;
Second Characters =
var _firstchars=
FILTER(
Customer,
[First character matched]=1
)
var _secondchars=
SELECTCOLUMNS(
ADDCOLUMNS(
_firstchars,
'second char',
RIGHT(LEFT(Customer[FullName],2),1)),
'char',[second char])
var _distictcharlist=

DISTINCT(_secondchars)
return
COUNTROWS(
FILTER(
_distictcharlist,
[char]=SELECTEDVALUE('2nd Char'[Character])
)
)
Third Characters
This measure filters the third character slicer with all possible options based
on the first and the second character slicer selections;
Third Characters =
var _firsttwochars=
FILTER(
Customer,
[First character matched]=1 && [Second character matched]=2

)
var _thirdchars=
SELECTCOLUMNS(
ADDCOLUMNS(
_firsttwochars,
'third char',
RIGHT(LEFT(Customer[FullName],3),1)),
'char',[third char])
var _distictcharlist=
DISTINCT(_thirdchars)

return
COUNTROWS(
FILTER(
_distictcharlist,
[char]=SELECTEDVALUE('3rd Char'[Character])
)
)

Filtering Visuals by Measures


Now, as the last step, we can filter visuals by their respective DAX
measure. Second Characters filter the Second Character slicer visual to be
1.

Third Characters filter the third character slicer to be 1.

The three measures filter the table visual; the First character matched, the
Second character matched, and the Third character matched to be equal to
1, 2, and 3, respectively.
The final result is as below;

Summary
Using parameter tables and filtering visuals based on DAX measures, you
can achieve interesting results. I’m sure a filter capability like the above
will be added soon in Power BI. However, until then, this can be a helpful
solution for you. On the other hand, it teaches you how you can combine
parameter tables, DAX, and filtering visuals to get some results out of the
standard possibilities of the tool.
Part 9: Parameter Table
Chapter 58: Power BI What If
Parameter for Getting the Sales of
X months ago: Use Case Scenario

There are two types of parameters in Power BI, Power Query


parameters[https://radacad.com/change-the-source-of-power-bi-datasets-
dynamically-using-power-query-parameters] and What if parameters. In
this chapter, I’m going to explain a handy use case of the what-if
parameters, and if you haven’t ever worked with it, it is a great way to
understand what is What If parameters and what things you can do with
them. The What If parameters are also called DAX parameters informally.

What If Parameters
There are two types of parameters in Power BI; Power Query parameters
and What If parameters. Power Query parameters are used for creating a
dynamic structure for the data transformation phase. Here is an example of
using Power Query parameters for changing the data source. Another
example is creating a custom function to loop through some steps for a
single data structure.
The What If parameters, on the other hand-side, are for end-users. It
empowers them to make changes and see the effect of their changes
immediately on the report. For example, let’s say you have written a DAX
expression that calculates sales of last month. After building the solution
using this calculation and delivering it to your users, they come to you and
ask you that can we have this calculation for two months ago? They come
after a while and ask if we can have it for three months or even six months?
The user is seeking a way to change a calculation by their selection in the
slicer. They want to see what would happen if they change some of the
values. They want to do a What IF analysis. That is precisely why this type
of parameter is called What If parameters. Let’s see that through an
example.

If the Power BI report user wants to do an analysis such


as WHAT would happen IF this value is different, you can
implement that using the What If Parameter.

Sales Last Month


The DAX measure below calculates the sales of last month.
Sales Last Month =
CALCULATE(
SUM(FactInternetSales[SalesAmount]),
PARALLELPERIOD(
DimDate[FullDateAlternateKey].[Date],
-1,
MONTH
)
)

Using the calculation above, you can see that we navigate one month back
using the -1 as the second parameter of the ParallelPeriod function to
calculate the last month's sales.
here is the result of that calculation:

For every month, the value of this measure would be the sales of the month
before that.

What If X Months?
After delivering a solution with the above calculation to your users, you
will likely get another request: what if I want to see the sales of 2 months
ago? Three months ago, five months, etc. What if I want to see the sales of
X months ago. You don’t expect end-users to go and change the “-1” in the
DAX expression to another number and get the result (even if they do have
the edit access to the report, or they do have Power BI Desktop installed). It
would be best if you gave them the ability to change the “-1” in the
expression above. And they do that by merely changing a value in a slicer.

Creating What If Parameter


You can easily create a What-If-parameter in Power BI Modeling tab.

For this purpose, the data type of the parameter can be the Whole number. I
named it “How Many Months Back”, and set the values as below. Having
the “Add slicer to this page” ensures that there will be a slicer created for
this parameter in the current report page.
After this step, you’ll see a new slicer created and a new table, column, and
measure with this name.
Power BI uses the GenerateSeries DAX function to create the list of values
as a calculated table when you make a parameter.
There is also a measure created with this new table that uses the
SelectedValue function to access the value selected by the slicer. You can
add that measure to a card visual and see how it changes when you change
the slicer value.

Using the Parameter Selected value in the


measure
Now that we have created the parameters, we can move to the next step,
which is using it to change the value of the measure to calculate sales of X
months ago;
Sales X Months ago =
CALCULATE(
SUM(FactInternetSales[SalesAmount]),
PARALLELPERIOD(
DimDate[FullDateAlternateKey].[Date],

-1*[How Many Months Back Value],


MONTH
)
)

Note that in the above expression, we have used the selected value measure
multiplied by -1. The reason is that our parameter is a positive value. Still,
for moving back a few months ago, we need a negative one. You can create
parameters with negative values too. However, it might not look great from
the user's point of view because they have to understand why the slicer
value is negative.

Testing the result


Now, simply with a change in the slicer, the calculation changes. You gave
the user the ability to calculate the sales of one month ago, two months,
three months, etc., using a What If parameter.
Summary
The What If parameters in Power BI are beneficial for creating a dynamic
DAX measure expression that changes based on the user selection. This can
help the user to understand what would happen if they change a value. You
can also create parameters of other data types (DateTime and Text), but the
graphical user interface doesn’t support those at the time of writing this
chapter. For those, you need to create your parameter table, which I’ll
explain that later in another chapter.
Chapter 59: Dynamically change
the format of values in Power BI

Can you change the format of a measure or a value in Power BI


dynamically? Is it possible to set a value as a percentage sometimes and
sometimes to be a currency? Can you change the currency format? The
answer to all these questions is yes. In this short chapter, I am going to
show you how you can do it.

Static formatting in Power BI


One way to format values (either columns or measures) is by the format
pane settings under the Column or Measure tools.

formatting for columns in Power BI


This method is a simple method that can work if you want to set the format
for a column or measure.
However, sometimes, you want to do things more dynamically. For
example, you might have users in different countries with different
formatting requirements.

DAX Format function


The Format function is straightforward in DAX. This function can be used
for generating some format options. The function can be used simply like
this:
FORMAT(SUM(Sales[Sales Amount]), '$#,##0')

The first parameter of the format function is the value to which we want the
formatting to be applied, and the second parameter is its format. There are
many formatting options available, which are suitable for number, date, etc.
Here is an excellent detailed guide about it;
Pre-Defined Numeric Formats for the FORMAT
function[https://docs.microsoft.com/en-us/dax/pre-defined-
numeric-formats-for-the-format-function?WT.mc_id=DP-
MVP-4030647]
Custom Numeric Formats for the FORMAT
function[https://docs.microsoft.com/en-us/dax/custom-
numeric-formats-for-the-format-function?WT.mc_id=DP-
MVP-4030647]
Pre-defined date and time formats for the
F[https://docs.microsoft.com/en-us/dax/pre-defined-date-and-
time-formats-for-the-format-
function]O[https://docs.microsoft.com/en-us/dax/pre-defined-
date-and-time-formats-for-the-format-function?
WT.mc_id=DP-MVP-4030647]RMAT
function[https://docs.microsoft.com/en-us/dax/pre-defined-
date-and-time-formats-for-the-format-function]
Custom date and time formats for the FORMAT
function[https://docs.microsoft.com/en-us/dax/custom-date-
and-time-formats-for-the-format-function?WT.mc_id=DP-
MVP-4030647]
Now, the FORMAT function can be combined with other methods to make
the dynamic formatting possible.

Parameter table
The parameter table is a disconnected table from the rest of the model. This
table can act like a parameter for other calculations. Here in the example
below, I showed how it could be used to select between measures:
Now, these two methods can work together to build dynamic formatting.

Parameter table for currency


Here I have created a parameter table for the currency values. This table can
be created anywhere; In Excel, another data source, or even in Power BI
Desktop.

Dynamic Format Measure


Then I created a measure that dynamically change the format using the
value selected from the table above;
Sales =
var _sales=SUM(FactInternetSales[SalesAmount])
return
FORMAT(_sales,
SWITCH(
SELECTEDVALUE('Currency'[Currency Format],'USD'),
'USD','$#,##0.##',
'GBP','£#,##0.##',
'Euro','€#,##0.##'
)
)

The code above checks what value is selected from the Currency table
(using the SELECTEDVALUE function) and then uses it inside a
conditional expression and assigns the equivalent currency's format string to
it (using the SWITCH function). Finally, this format string is used inside a
FORMAT function to format the measure’s value.
The below screenshot is a glimpse of the result;

Taking it a few steps further


When you use DAX for making things dynamic, then you can always do
amazing things. Here is an example:
I created two other tables, one for the Thousand separator;

And one for Decimal places;

And I used an expression like below;


Sales with dynamic formatting =
var _sales=SUM(FactInternetSales[SalesAmount])
var _thousandSeparator=IF(
SELECTEDVALUE('Thousand separator'[Enable])='yes',
',')
var _decimalplaces=REPT('#',SELECTEDVALUE('Decimal places'[Decimal places],2))
var _NumericFormat='#'&_thousandSeparator&'##0'
&if(
SELECTEDVALUE('Decimal places'[Decimal places],2)>0,

'.'&_decimalplaces)
return
FORMAT(_sales,
SWITCH(
SELECTEDVALUE('Currency'[Currency Format],'USD'),
'USD','$',
'GBP','£',
'Euro','€'
)&_NumericFormat
)

This means that now we can have dynamic formatting like below in Power
BI. This allows enabling or disabling the thousand-separator, removing or
adding decimal places, and currency change.
dynamic formatting in Power BI

Consideration
A critical consideration of using this method is that the return value of your
measure or column would be of the TEXT data type (within the format
string defined).
Part 10: Parent-Child Functions
Chapter 60: Parsing Organizational
Hierarchy or Chart of Accounts in Power
BI with Parent-child Functions in DAX

Parent-child functions in DAX are beneficial for parsing an organizational


hierarchy or something like a chart of accounts. Usually, for hierarchies that
the number of levels is not determined, you need to use a different method,
and parent-child functions in DAX are a big help for that type of hierarchy.
This chapter will learn what functions are involved in this class of
functions. The same method can be used for a chart of accounts.

Introduction
Organizational charts or the chart of accounts are specific types of
hierarchy. Because it is not usually apparent how many hierarchy levels you
get, the hierarchy structure is stored in two columns across the table; ID and
Parent ID. ID usually points to the existing row as the unique key, and
Parent ID usually means to another row in the same table as the ID of
manager, parent, or higher level’s member. Only these two columns
together build the hierarchy. Here is an example;
DAX has a set of functions named Parent-child functions handy for parsing
this type of hierarchy. Let’s see how these functions work.
Sample Dataset
If you want to walk through the example of this chapter, create a new Power
BI Desktop file, and get data from AdventureWorksDW and select
DimEmployee as the only table to get data from.

Path Function: Finding the entire path


from one member
The first function is named Path. This function gets two parameters; ID and
Parent ID. The Path is a very simple function to use. You need to create a
calculated column with this function with the code below;
Path = PATH(DimEmployee[EmployeeKey],DimEmployee[ParentEmployeeKey])

Here is the result;


As you can see, the output column has all the hierarchy from the current
member. The first record’s data means: the current record’s ID is 1, the
manager of that is the record with ID of 18, and the manager of that is the
record with ID of 23, and then the top-level manager is 112. You can see
112 is the top-level manager in all records as well.

Finding the Length of Path; PathLength


Function
Your next step is to find out how many levels of management you have in
the hierarchy. You can use PathLength Function to find out the count of
levels for each row. Create a calculated column with the PathLength
function. This function gets the result of the Path function as the input to
use the column created in the previous step as the input of this function.
Path Length = PATHLENGTH(DimEmployee[Path])

Here is the result;

To find out the size of the hierarchy, you need to find out the maximum
PathLength value. You can create a report visual and show Maximum of
Path Length field to see the maximum number of levels in your dataset.
As you can see, the maximum number of levels in the example dataset in
this chapter is 5.

PathItem; Finding specific levels of the


hierarchy
The next step is to create a column for each level of the hierarchy. Using
PathItem, you can find out the item for each level of the hierarchy. PathItem
gets three parameters;
The output of the Path function; which we can use our Path
calculated column for it.
The position of the item. Starting from 1, 1 means the highest
level (big boss in the organizational hierarchy)
The output’s data type. 1 means number, 0 means text. We
need a number output (to search the employeekey in the table
based on that later on), so we use 1 as the input here.
The code will be a calculated column as below;
Organization Level 1 = PATHITEM(
DimEmployee[Path],
1,
1)

Here is the sample output;

As you can see, 112 is the ID of the big boss and the first level of
management in the Path column.
PathItemReverse; start from the lowest level
If you don’t want to start from the highest level, you can use the
PathItemReverse function. Everything will be similar to using the PathItem
function; the only difference is that this time, the position starts with index
1 for the lowest level of the hierarchy.
LookupValue; to find the name of the
employee
Having just the ID of the manager is not usually enough. You may need to
get the name of the employee too. In the DimEmployee table, we do not
have a full name field. So first add a full name field as below;

Now you can use the LookupValue function to get the employee's full name
that we found by the PathItem function. LookupValue asks for three
parameters;
The output column
The column to search into for the keyword
the keyword (keyword in our scenario is coming from the
result of the PathItem function)
Here is the code altogether for organization level 1:
Organization Level 1 =
LOOKUPVALUE(
DimEmployee[FullName],
DimEmployee[EmployeeKey],
PATHITEM(

DimEmployee[Path],
1,
1)
)

and the result is as below;


Create one column per hierarchy levels
Finally, you need to create one column per hierarchy level. All you need to
do is copy the code for PathItem and LookupValue and only change the
position parameter. Here is the final result for five levels;
You can then visualize this data using any visuals, but hierarchy slicer
custom visual provides a nice output like below, and it acts like a slicer too;
PathContains
We talked about all Parent-child functions in this example, except
PathContains. PathContains is a function that searches through a path for an
ID. One example usage of this function is to apply dynamic Row Level
Security for an organizational chart. Here in this
post[https://radacad.com/dynamic-row-level-security-with-organizational-
hierarchy-power-bi], I wrote a complete example of using the PathContains
function for RLS.

Summary
Parent-child functions in DAX are simple to use but very powerful and
functional in Power BI and DAX. Using these functions will allow you to
parse hierarchies such as organizational charts or the chart of accounts in a
recursive mode. In this chapter, you have seen an example of using parent-
child functions for parsing an organizational chart.
Book wrap up
Congratulations on finishing the book. I hope you enjoyed reading, and this
book took you through some of the pathways to learn DAX. Always
remember that there are many ways to accomplish a calculation in DAX.
Happy DAXing!
To leverage the learnings from this book, I encourage you to start applying
the learning right away in your Power BI implementations. If you feel
concerned or have a question about a particular scenario, feel free to reach
out to me directly using RADACAD website[https://radacad.com/], I’d be
more than happy to look into your question.
Wishing you the best
Reza Rad
July 2021
Other books from Reza Rad
Power BI from Rookie to Rock Star
This is a series of four books, over 1200 pages, available for free to
download from here [https://radacad.com/online-book-power-bi-from-
rookie-to-rockstar]

Row-Level Security in Power BI


Here[https://www.amazon.com/Row-Level-Security-Power-BI-different-ebook/dp/B082SFR2J4]
Pro Power BI Architecture
Here[https://www.amazon.com/Pro-Power-Architecture-Deployment-Microsoft-
ebook/dp/B07KQZ1ZDR]
Basics of Power BI Modeling
Here [https://www.amazon.com/gp/product/B08HWNZ7GC]

You might also like