©  Adam Aspin 2018
Adam AspinPro Power BI Desktophttps://doi.org/10.1007/978-1-4842-3210-1_12

12. Adding Measures to the Data Model

Adam Aspin
(1)
Stoke-on-Trent, Staffordshire, UK
 
Adding new columns can provide much of the extra data that you want to output in tools like Power BI Desktop. It is unlikely, however, that this approach can deliver all the analyses that you need. Specifically, calculated columns can only work on a row-by-row basis; they cannot contain formulas that have to apply to all or part of the records in a table. For instance, counting the number of cars sold for a year, a quarter, or a month has nothing to do with the data in a single row in the Stock table. It does, however concern the table as a whole.
Generally, you need to add a second type of formula to your tables when you have to look at subsets of the data. These formulas are called, simply, measures . These calculations (or measures or metrics—call them what you will) also use DAX. They are applied differently, though, and they can produce some extremely powerful results to help you analyze your data. This is because measures do things that calculated columns simply cannot do. So if you need to work with aggregate values and not on a row-by-row basis , then you will have to create measures to achieve the correct result.
As with so many aspects of Power BI Desktop and self-service business intelligence in general, measures are probably best introduced through a few examples. Unfortunately, it is impossible to do anything other than scratch the surface of measures in only a few pages, because they are arguably the most powerful element in Power BI Desktop—one that deserves an entire book to itself. Nonetheless, I hope that this short introduction will whet your appetite, and that you will then continue to learn all about DAX and its more advanced application from the many excellent resources currently available.
In this chapter, we continue to develop the file that you began in the previous chapter. The file with all the columns that were added in the previous chapter is available for download as C:PowerBiDesktopSamplesCH12CarSalesDataWithNewColumns.pbix.

A First Measure: Number of Cars Sold

Suppose that you want to be able to display the number of cars sold in Power BI Desktop. Not only that, but you want this figure to adjust when it is filtered or sliced by another criterion, such as country or color. Put simply, you want this metric to be infinitely sensitive to how it is displayed, yet always give the right answer.
So how are we going to achieve this? The following explains how:
  1. 1.
    Open the Power BI Desktop file C:PowerBiDesktopSamplesCH12CarSalesDataWithNewColumns.pbix.
     
  2. 2.
    Ensure that you are in Data View (the middle of the view icons on the left below the ribbon).
     
  3. 3.
    Select the table to which you wish to add a measure. I chose Stock here.
     
  4. 4.
    In the Modeling ribbon, click the New Measure button. The formula bar will look like Figure 12-1.
    A370912_2_En_12_Fig1_HTML.jpg
    Figure 12-1.
    The formula bar when creating a measure
     
  5. 5.
    Add the following formula to the formula bar:
    NumberOfCarsSold=COUNTROWS (
    You will see that the popup will then suggest a list of DAX formulas interspersed with the names of tables in the current data model. If you scroll down the list, it will look like Figure 12-2.
    A370912_2_En_12_Fig2_HTML.jpg
    Figure 12-2.
    The popup menu showing functions and tables
     
  6. 6.
    Select the table Stock and add the right parenthesis. The formula will look like this:
    NumberOfCarsSold = COUNTROWS(Stock)
     
  7. 7.
    Confirm the creation of the formula by pressing Enter or by clicking the check mark icon in the formula bar. A new field will appear in the Fields list after any existing fields for the Stock table.
     
Assuming that you have just read Chapter 11, the first thing that will strike you in comparison with creating a new column is that no column is created for this measure. The only indication that it exists is its presence in the Fields list once you expand the Stock table. If you look closely at the field (NumberOfCarsSold ) that you have just created, you will also see that there is a tiny icon of a calculator to the left of the field name. This allows you to distinguish measures from new columns (which have a small Fx icon to the left of the field name).
Not difficult, I am sure you will agree. Yet the best is yet to come. Suppose that you now use this field in a Power BI Desktop card (you saw these briefly in Chapter 1, and can see them in more detail in Chapter 15). The result is filtered so that only the number of sales for 2014 is displayed. In other words, the formula is completely separate from the data in a column, but applies any filters that are selected. You can see this applied to a visualization in Figure 12-3.
A370912_2_En_12_Fig3_HTML.jpg
Figure 12-3.
Using a measure in a card visualization
The key thing to take away is that a correctly applied measure can be used in a Power BI Desktop table, chart, or indeed any type of visualization, and always shows the correct result of any and all filters and slicers that you have applied. Also, the figures are correct for each intersection of rows and columns in tables. All in all, it is well worth ensuring that you have all the measures that you need for your analytical output in place and that they are working correctly in Power BI Desktop, because you can then rely on these calculations in the dataset in many different visualizations across a series of reports.
Tip
You can rename measures by either right-clicking the name of the measure in the Fields list and selecting Rename, or by clicking the name of the measure in the Fields list and altering the name in the formula bar.
When you start out creating measures, it can be a little disconcerting at first not to see the results of a formula immediately, as you can when adding new columns. If this worries you (or if you want to test the result of a new measure), then one approach is to create a table in Dashboard View and add the new measure plus any other useful measures that allow you to verify that everything works as you expected. This technique was outlined briefly in Chapter 1 and is explained in detail in Chapter 14.

Basic Aggregations in Measures

Measures are DAX formulas, so in learning to use measures you will have to become familiar with some more DAX functions. My intention here, though, is definitely not to take you through all that DAX can offer. Instead, I would like to show you a few basic formulas that can be useful in real-world dashboards and give you some initial DAX recipes that should prove practical.
So, as a second example, let’s calculate total costs of vehicles purchased. Although you can just type in a simple DAX formula, I prefer to show you how you can extend the knowledge that you gained when creating calculated columns and apply many of the same techniques to creating measures.
  1. 1.
    In Power BI Desktop, ensure that you are in Data View.
     
  2. 2.
    Select the Stock table and click the New Measure button in the Modeling ribbon.
     
  3. 3.
    Replace Measure with the name that you want to use (Total Sales).
     
  4. 4.
    Click to the right of the equals sign (=).
     
  5. 5.
    Enter SUM as the function, followed by a left parenthesis. A list of all the tables and fields in the data model will appear (including any columns and measures that you have added).
     
  6. 6.
    Enter a left bracket to restrict the popup list to fields in the current table.
     
  7. 7.
    Start typing the field name (CostPrice in this example). After a couple of characters, any tables or fields with these characters will be listed, as shown in Figure 12-4.
    A370912_2_En_12_Fig4_HTML.jpg
    Figure 12-4.
    Creating a measure containing an aggregation
     
  8. 8.
    Scroll down and select the [CostPrice] field.
     
  9. 9.
    Add a right parenthesis. The formula should read:
    TotalSales=SUM(Stock[CostPrice])
     
  10. 10.
    Press Enter (or click the check mark icon in the formula bar).
     
  11. 11.
    Format the new column appropriately (I have used pounds sterling).
     
The measure is created and it appears in the Fields list. This particular function gives you the total of the SalePrice column. However, when you use it in Power BI Desktop, it is filtered and applied (or sliced and diced if you prefer) to take into account how the data is subset.
One important thing to note when creating measures is that you should use the table name as well as the field name if there are fields that have the same name in several tables. This is so that Power BI Desktop is certain that it is using the right field from the right table. What’s more, if a table name contains spaces, then the table name needs to be in single quotes. In all cases, the field name has to be enclosed in square brackets.
To practice a little (and to prepare the ground for some eye-catching visualizations in Chapters 1422), try creating the average, maximum, and minimum sale price using the formulas in Table 12-1.
Table 12-1.
A Few Elementary DAX Measures
Name
DAX Code
Average Cost Price
AVERAGE(Stock[CostPrice])
Maximum Sale Price
MAX(InvoiceLines[SalePrice])
Minimum Sale Price
MIN(InvoiceLines[SalePrice])

Using Multiple Measures

As you can well imagine, not all metrics are likely to be as simple as those that you just saw. You can also create measures that are the result of combining several DAX functions.
For a little practice, you could try adding the ratio of gross margin to sale price to the data model. This measure will then be used in the upcoming chapters on creating dashboards with Power BI Desktop. If you do not want to create this measure step by step, then you can jump to step 13 and type or paste the formula into the formula bar.
  1. 1.
    In Power BI Desktop, ensure that you are in Data View.
     
  2. 2.
    Select the InvoiceLines table and click the New Measure button in the Modeling ribbon.
     
  3. 3.
    Replace Measure with the name that you want to use (RatioNetMargin).
     
  4. 4.
    Click to the right of the equals sign (=).
     
  5. 5.
    Enter SUM as the function, followed by a left parenthesis.
     
  6. 6.
    Enter a left bracket to limit the list to fields in the current table.
     
  7. 7.
    Select the [Gross Margin] field.
     
  8. 8.
    Enter a right parenthesis.
     
  9. 9.
    Enter a forward slash (the divide-by operator).
     
  10. 10.
    Enter SUM as the function, followed by a left parenthesis.
     
  11. 11.
    Enter a left bracket to limit the list to fields in the current table.
     
  12. 12.
    Select the [SalePrice] field.
     
  13. 13.
    Enter a right parenthesis. The formula should read
    RatioNetMargin = SUM([Gross Margin])/SUM([SalePrice])
     
  14. 14.
    Press Enter (or click the check mark icon in the formula bar).
     
  15. 15.
    Power BI Desktop should guess that this is a ratio, and format the column as a percentage accordingly. If it does not, in the Modeling ribbon, click the percentage button to apply a percentage format.
     
The easiest way to see the output of a measure like this is to create a table that uses the measure and another attribute so that you can see how the measure works in practice. Figure 12-5 shows a simple example of this, but for all years’ data.
A370912_2_En_12_Fig5_HTML.jpg
Figure 12-5.
Applying a measure in a table
This is an extremely simple example of a composite DAX function, of course. Indeed, you can probably see a distinct resemblance to an Excel formula. However, the key point to take away is that once you have created the measure, it will work in just about any Power BI Desktop visualization and using most, if not all, of the attributes from the data model. Power BI Desktop can also apply the measure intelligently to hierarchies of data. So, for instance, if you add the Make field to Table 12-1 and switch the visualization to a matrix, you will instantly see the calculations that are shown in Figure 12-6. Here, Power BI Desktop has automatically calculated the net margin ratio for each vehicle sold without your having to alter the formula in any way.
A370912_2_En_12_Fig6_HTML.jpg
Figure 12-6.
A hierarchy using a measure
When you use measures like this one in visualizations, you may well find that some calculations are displayed to many decimal places. If you find this distracting, then you can format measures in the same way that you format Power BI Desktop columns. Any formats that you apply are used in Power BI Desktop by default whenever you use this measure.
A final point. When you insert a table or a field from the popup list shown in Figure 12-4, you see three types of icons to the left of the table or field: the icon with a table outline denotes a Power BI Desktop table; the table with a selected column icon indicates a column of data or a column that you have added; a calculator icon indicates an existing measure.

Cross-Table Measures

You are not limited to creating measures that refer to the fields in a single table. If anything, measures are designed to apply across all the fields in a data model. To start out with a simple example, suppose that you want to create a custom measure that displays the margin for each vehicle once the cost price and any cost of spares have been deducted. If you just want to type in the formula, then jump directly to step 12.
  1. 1.
    In Power BI Desktop, ensure that you are in Data View (the middle of the view icons on the left below the ribbon).
     
  2. 2.
    Select the InvoiceLines table and click the New Measure button in the Modeling ribbon.
     
  3. 3.
    Replace Measure with the name that you want to use (Cost Plus Spares Margin).
     
  4. 4.
    Click to the right of the equals sign (=).
     
  5. 5.
    Enter SUM as the function, followed by a left parenthesis. A list of all the tables and fields in the data model will appear (including any columns and measures that you have added).
     
  6. 6.
    Select InvoiceLines[SalePrice].
     
  7. 7.
    Add a minus sign after the formula (you can add spaces before and afterward if you want).
     
  8. 8.
    Enter SUM as the function, followed by a left parenthesis. A list of all the tables and fields in the data model will appear (including any columns and measures that you have added).
     
  9. 9.
    Select InvoiceLines[SalePrice].
     
  10. 10.
    Add a minus sign after the formula (you can add spaces before and afterward if you want).
     
  11. 11.
    Enter SUM( and then expand the Stock table in the Fields list and click the CostPrice field.
     
  12. 12.
    Add a right parenthesis. The formula will look like this:
    Cost Plus Spares Margin = SUM(InvoiceLines[SalePrice]) - SUM(Stock[CostPrice]) - SUM(Stock[SpareParts])
     
  13. 13.
    Press Enter (or click the check mark icon in the formula bar).
     
You could then add this new measure to the matrix that you saw previously. If you do, you see something like Figure 12-7.
A370912_2_En_12_Fig7_HTML.jpg
Figure 12-7.
Cross-table measures
Creating cross-table measures in DAX is easier than creating new columns that use values from more than one table. From this example, you can see the following:
  • You do not need to use the RELATED() function.
  • You only have to specify the table name before entering the field name (or select the combination of table and field from the popup).
  • You can use the Fields list to refer to fields in other tables (or even in the same table).
  • You must use aggregation functions on numeric fields. If you do not, you will get an error message.
Note
A measure is attached to a table so that it appears as a field in the specific table. The measure does not have to use any of the fields in the table that “hosts” it. This means that you can attach measures to any table in your data model, which allows for a considerable organizational freedom when extending the model with further metrics. Moreover, you can move measures between tables if you want.
Tip
You can even create an otherwise empty table (using the technique that you saw in Chapter 2) to serve as a container for measures.

More Advanced Aggregations

Now that you have seen how to create basic measures, it is time to move on to some more advanced concepts. More precisely, I want to outline a couple of ways to aggregate data on a row-by-row basis , yet return the result with any filters and slicers applied. There are many cases where this cannot be done using a calculated column and then returning the aggregate of the column data. After all, you need to return the ratio of the sum of any values and not the sum of the ratio. Think of calculating a ratio for each row and then averaging the results to get the average ratio; it is arithmetically false.
Fortunately, Power BI Desktop has some simple yet powerful solutions to this kind of conundrum. One principal tool is the use of the “X” functions—AVERAGEX(), COUNTX(), SUMX(), MAXX(), and MINX(), among others. These functions allow you to specify
  • The table in which the calculations apply
  • The row-by-row calculation that is to be applied
As an example, consider the requirement for the ratio of the cost of any parts compared to the purchase price of each vehicle. Not only do we need this potentially at the finest level of granularity—the individual record—but we may need it sliced and diced by any number of criteria. To extend your knowledge, we will also create this measure directly in the Report View, without stepping sideways into the Data View . The following explains how to create the formula that you could use in Power BI Desktop reports (and step 15 contains the final formula if you only want this):
  1. 1.
    In Power BI Desktop , ensure that you are in Report View (the topmost of the view icons on the left below the ribbon).
     
  2. 2.
    Select the Stock table in the Fields list and click the New Measure button in the Modeling ribbon.
     
  3. 3.
    Replace Measure with the name that you want to use (Average Parts Cost Ratio).
     
  4. 4.
    Click to the right of the equals sign (=).
     
  5. 5.
    Enter AVERAGEX as the function, followed by a left parenthesis. A list of all the tables and fields in the data model will appear (including any columns and measures that you have added).
     
  6. 6.
    Select the Stock table.
     
  7. 7.
    Enter a comma.
     
  8. 8.
    Add a left parenthesis. This is to ensure that the subtraction is carried out before the division.
     
  9. 9.
    Enter a left bracket and select the [CostPrice] field or enter the field name, including the square brackets.
     
  10. 10.
    Add a minus sign after the field name (you can add spaces before and after if you want).
     
  11. 11.
    Enter a left bracket and select the SpareParts field or enter the field name including the square brackets.
     
  12. 12.
    Enter a right parenthesis. This matches the opening left parenthesis in step 7.
     
  13. 13.
    Add a forward slash (the divide-by operator).
     
  14. 14.
    Enter a left bracket and select the [SpareParts] field or enter the field name, including the square brackets.
     
  15. 15.
    Enter a right parenthesis. This finishes the AVERAGEX() function. The formula will look like this:
    Average Parts Cost Ratio = AVERAGEX(Stock,([CostPrice]-[SpareParts]) / [SpareParts])
     
  16. 16.
    Press Enter (or click the check mark icon in the formula bar).
     
Just creating the formula is pretty meaningless. So take a look at the chart in Figure 12-8, where you can see how this ratio instantly shows you which models are the most costly as far as spare parts are concerned.
A370912_2_En_12_Fig8_HTML.jpg
Figure 12-8.
Using the AVERAGEX() function in DAX
As you can see from this example—and unlike the AVERAGE() function—AVERAGEX() takes two inputs (or parameters as they are technically known):
  • The table to which the formula is applied
  • The formula to use, which is just as you would apply it to a calculated column
This formula deducts the CostPrice from the SalePrice for every row in the table, and then returns the average dependent on the filters and selections currently applied. This way, you always get the mathematically accurate result in your visualizations.
The following are the essential points to take away from this example:
  • It is essential to wrap any field references in an aggregate function, such as SUM(), AVERAGE(), or COUNT(), for an aggregated result to work. This is because the calculation (depending on the filters used) is not applied to only one record, but potentially several records, so data must be aggregated. Hence, the use of the SUM() function in this example.
  • You can, and indeed, must, nest calculations inside parentheses to force Power BI Desktop to calculate elements in the correct order. This functions exactly as it does in Excel, so I will not labor the point here.
There are many more of these “X” functions (which are generally known as iterative functions, as they iterate over an entire table) in Power BI. Table 12-2 outlines those that are currently available.
Table 12-2.
DAX Iterative Functions
Formula
Description
Example
MINX()
Calculates a value for each row in a table and displays the minimum value.
MINX(Stock, [PartsCost]+[LaborCost])
MAXX()
Calculates a value for each row in a table and displays the maximum value.
MAXX(Stock, [PartsCost]+[LaborCost])
SUMX()
Calculates a value for each row in a table and displays the total.
SUMX(Stock, [PartsCost]+[LaborCost])
AVERAGEX()
Calculates a value for each row in a table and displays the average of these values.
AVERAGEX(Stock, [PartsCost]+[LaborCost])
COUNTX()
Calculates a value for each row in a table and counts the resulting rows, including non-blank results of the calculation.
COUNTX(Stock, [PartsCost]+[LaborCost])
COUNTAX()
Calculates a value for each row in a table and counts the resulting rows, not including non-blank results of the calculation.
COUNTAX (Stock, [PartsCost]+[LaborCost])
GEOMEANX()
Calculates a value for each row in a table and displays the geometric mean of these values.
GEOMEANX(Stock, [PartsCost]+[LaborCost])
MEDIANX()
Calculates a value for each row in a table and displays the median value of these values.
MEDIANX(Stock, [PartsCost]+[LaborCost])
PERCENTILEX.EXC()
Returns the percentile of a record relative to the dataset.
PERCENTILEX.EXC(Stock, [PartsCost]+[LaborCost])
PERCENTILEX.INC()
Returns the percentile of a record relative to the dataset.
PERCENTILEX.INC(Stock, [PartsCost]+[LaborCost])
RANKX()
Orders the rows by progressive rank.
RANKX(ALL(Stock[Make]), SUMX(RELATEDTABLE(InvoiceLines), [SalePrice]))
STDEVX.P()
Calculates a value for each row in a table and displays the standard deviation of the entire population of these values.
STDEVX.P(Stock, [PartsCost]+[LaborCost])
STDEVX.S()
Calculates a value for each row in a table and displays the standard deviation of a sample population of these values.
STDEVX.S(Stock, [PartsCost]+[LaborCost])
VARX.S()
Calculates a value for each row in a table and displays the variance of the entire population of these values.
VARX.S(Stock, [PartsCost]+[LaborCost])
VARX.P()
Calculates a value for each row in a table and displays the variance of the entire population of these values.
VARX.P(Stock, [PartsCost]+[LaborCost])
PRODUCTX()
Returns the product of an expression evaluated for each row in a table.
AVERAGEX(Stock, [PartsCost], 0.1)

Filter Context

When working with DAX (at least if you want to develop any complex formulas), you need to understand filter context. This is the basis of the dynamic data analysis using Power BI Desktop. It is the basis of the approach where the results of a formula can change to reflect the current row or cell selection and any related filters.
Filter context can become an extremely complicated subject. However, since this is not a book on DAX, I am deliberately simplifying some of the ideas explained later in this chapter. After all, the aim is to get you started with DAX, not to scare you off right at the start.
The following are three key elements that you need to understand:
  • Row context
  • Query context
  • Filter context
Let’s take a brief look at these in turn.

Row Context

Row context is essentially the values from the current row. You saw this when creating new columns. This means that any fields that you used in a calculation always used other fields from the same record—or from a linked table . Therefore, this is largely automatic and typically handled by DAX without any intervention on your part.

Query Context

Query context is the combination of the following factors that produce a calculated result:
  • Report-level filters (including roles)
  • Page-level filters
  • Visualization-level filters
  • Slicers
  • Interactive selection
  • Row and column filters
The first three are cumulative (report-level filters, page-level filters, and visualization-level filters), and reduce the available data that a visualization can show. They are explained in detail in Chapter 20. For the moment, just consider them as a set of filters that only allows certain data to be used.
Slicers are any interactive filtering that you add for a dashboard. These restrict even further the dataset resulting from any report-level filters, page-level filters, and visualization-level filters to reduce even further the data that can be displayed. Interactive selection is a method of filtering data by selecting an element in another visualization. Both of these techniques are explained in detail in Chapter 21.
Row and column filters are best thought of as the row and column headers in a pivot table (or a cross-tab, if you prefer). These define the intersections of data that can be shown.
Query context is the cumulative effect of any filters that you apply when creating Power BI reports using the Power BI Desktop interface.

Filter Context

Filter context is added when you specify filter constraints on the set of values allowed in a column or table, by using formulas that expand or reduce the dataset that is used to obtain a result. Filter context applies on top of other contexts, such as row context or query context. This is the focus of the next few pages.

Filtering Data in Measures

Inevitably, there will be times when the filters that you apply using the Power BI Desktop user interface (the query-level filters that were described earlier) are not quite what you are looking for. There could be several reasons for this, including the following:
  • You want to apply a highly specific filter to a single metric.
  • You want to override the natural result of the query-level filter.
  • You are creating a highly complex formula and it has to be tailored to a specific use.
Any of these reasons (and there are many others that you will discover as you progress with DAX) could require you to filter the data in a measure. Let’s look at a few circumstances where this could prove necessary. Given the wide-ranging possibilities of DAX, I do not intend to explain anything more than the basics of DAX filtering using a few simple examples that I hope you find practical when building your own dashboards.

Simple Filters

There will probably be many occasions in your career when you need to home in on a specific subset of data. Maybe you need to compare and contrast one sales stream with another. Perhaps you need to highlight one cost compared to a total. Whatever the actual requirement, you need to apply a specific filter to a metric.
There are dozens—if not hundreds—of ways of applying different filters when building measures. However, one function is definitely an essential part of your DAX toolbox: the CALCULATE() function. This function lets you apply a range of filters to a measure that you can then apply in the visualizations that you build into your dashboards.

Text Filters

To begin, let’s look at a fairly simple filter requirement. Brilliant British Cars sells to two types of clients: dealers and wholesalers. As part of your ongoing sales analysis, you want to isolate the dealer sales stream. The following explains how you can do this. Take a look at step 12 if all you want is the final formula.
  1. 1.
    Click the InvoiceLines table in the Fields list.
     
  2. 2.
    In the Modeling ribbon, click the New Measure button.
     
  3. 3.
    In the formula bar, replace Measure with DealerSales.
     
  4. 4.
    To the right of the equals sign, enter (or select) CALCULATE(.
     
  5. 5.
    Enter (or select) SUM(.
     
  6. 6.
    Select the InvoiceLines[SalePrice] field.
     
  7. 7.
    Add a right parenthesis. This will terminate the SUM() function.
     
  8. 8.
    Enter a comma. This tells the CALCULATE() function that you are about to add the filters.
     
  9. 9.
    Select the Clients[ClientType] field.
     
  10. 10.
    Enter an equals sign.
     
  11. 11.
    Add the word “Dealer” (include the double quotes).
     
  12. 12.
    Add a right parenthesis . This will terminate the CALCULATE() function. The formula should now read as follows:
     
DealerSales = CALCULATE(SUM(InvoiceLines[SalePrice]),Clients[ClientType]="Dealer")
You could then add this new measure to a simple table of sales by make. If you do, you will see something like Figure 12-9.
A370912_2_En_12_Fig9_HTML.jpg
Figure 12-9.
Using a simple filter
You can see from this table that the SalePrice column is not filtered in any way. However, the DealerSales column always shows a smaller figure for the sales per make, as it is displaying only the filtered subset of data that you requested. The new measure that you created can be applied to any visualization and can be filtered, sliced, and diced like any other data column, calculated column, or metric.
Now let me explain. Here we are using a function in DAX called CALCULATE(). This function does what its name implies: it calculates an aggregation. However, the calculation is nearly always a filter operation. This is because of the way in which its two parameters work:
  • The first parameter defines the function to use (SUM() and AVERAGE() here), and the table and column that is aggregated; it could have been potentially a much more complex formula.
  • The second parameter is a filter to force DAX to show only a subset of the data. In this specific case, it returns the sum of sales only when the client is a car dealership.
The filter that is applied here comes from another column . Indeed, it comes from another table altogether. When using the CALCULATE() function, you can use just about any column (either an original data column or a calculated column) as the source for a filter.
Note
When you are filtering on a text (such as the type of dealer in this example), you must always enclose the text that you are searching for in double quotes.

Numeric Filters

You are not restricted to filtering on text-based data only in Power BI Desktop. You can also subset data by numeric values. As an example, suppose that you want to see totals for sales for lower-priced models so that you can target the higher end of the market. The following explains how you could do this. Take a glance at step 12 if all you want is the final formula.
  1. 1.
    Click the InvoiceLines table in the Fields list.
     
  2. 2.
    In the Modeling ribbon, click the New Measure button.
     
  3. 3.
    In the formula bar, replace Measure with LowPriceSales.
     
  4. 4.
    To the right of the equals sign, enter (or select) CALCULATE(.
     
  5. 5.
    Enter (or select) SUM(.
     
  6. 6.
    Select the InvoiceLines[SalePrice] field.
     
  7. 7.
    Add a right parenthesis. This will terminate the SUM() function.
     
  8. 8.
    Enter a comma. This tells the CALCULATE() function that you are about to add the filters.
     
  9. 9.
    Select the InvoiceLines[SalePrice] field again.
     
  10. 10.
    Enter a less-than sign: <.
     
  11. 11.
    Enter 50000.
     
  12. 12.
    Add a right parenthesis. This will terminate the CALCULATE() function. The formula should now read
     
LowPriceSales = CALCULATE(SUM(InvoiceLines[SalePrice]),
InvoiceLines[SalePrice] < 50000)
Comparing the low-price sales with the unfiltered sales per 2015 make and model produces a table like the one in Figure 12-10.
A370912_2_En_12_Fig10_HTML.jpg
Figure 12-10.
Using a numeric filter
In this simple example you saw how to use the less than (<) comparison operator. You can use any of the standard logical comparison operators (=, <, >, <=, >=, <>) that you saw in the previous chapter.
Note
When you are filtering on a number , you must not enclose the number that you are searching for in quotes. Neither must you format the number in any way.

More Complex Filters

In the two previous examples, you saw the basics of creating filtered measures using either a text or a number to subset the data returned by the CALCULATE() function. In the real world of data analysis, filters can get a lot more complex. Indeed, allowing you to create specific and complex filters for metrics is one of the ways that DAX can help you tease out real insight from your data. So without attempting to get overly complicated, next are a few examples of the ways that you can define more complex filtered metrics in your data models.

Multiple Criteria in Filters

The CALCULATE() function is not limited to a single filter. Far from it. You can add multiple filters to the second part of this function, each separated by a comma.
For example, imagine that you not only want to see dealer sales when you look at your data, but also want to see the (slightly lower) figure for dealer sales where the client has a good credit status. This means combining two filter criteria.
  1. 1.
    Click the InvoiceLines table in the Fields list.
     
  2. 2.
    In the Modeling ribbon, click the New Measure button.
     
  3. 3.
    In the formula bar, replace Measure with Creditworthy DealerSales.
     
  4. 4.
    To the right of the equals sign, enter (or select) CALCULATE(.
     
  5. 5.
    Enter (or select) SUM(.
     
  6. 6.
    Select the InvoiceLines[SalePrice] field.
     
  7. 7.
    Add a right parenthesis. This will terminate the SUM() function.
     
  8. 8.
    Enter a comma. This tells the CALCULATE() function that you are about to add the filters.
     
  9. 9.
    Select the Clients[ClientType] field.
     
  10. 10.
    Enter an equals sign.
     
  11. 11.
    Add the word “Dealer” (include the double quotes).
     
  12. 12.
    Enter a comma. This indicates that you are adding another filter criterion.
     
  13. 13.
    Select the Clients[IsCreditWorthy] field.
     
  14. 14.
    Enter an equals sign.
     
  15. 15.
    Add the word TRUE(). This is a logical value; it does not need to be enclosed in quotes and it has an empty parenthesis added.
     
  16. 16.
    Add a right parenthesis. This will terminate the CALCULATE() function. The formula should now read
     
Creditworthy DealerSales = CALCULATE(SUM(InvoiceLines[SalePrice]),Clients[ClientType]="Dealer",Clients[IsCreditWorthy]=TRUE())
If this column is added to the table that you saw in Figure 12-9 , you will see a result something like the one in Figure 12-11.
A370912_2_En_12_Fig11_HTML.jpg
Figure 12-11.
Using a more complex filter
If anything, this was a simple example. The filters that you add to any measure that uses the CALCULATE() function can contain multiple elements. Also, you can create a series of filters where each filter element compares data from different tables and mixes both text-based and numeric filters.

Using Multiple Filters

For a final filter example, imagine that you want to isolate the percentage of creditworthy dealer sales relative to dealer sales. You can do this by using the two measure calculations (DealerSales and CreditworthyDealerSales ) in a single measure to obtain the desired result.
Since you just saw how to create these calculations, I will only show you the formula here:
Creditworthy DealerSales Percent = CALCULATE(SUM(InvoiceLines[SalePrice]),
Clients[ClientType]="Dealer",Clients[IsCreditWorthy]=TRUE()) /     
CALCULATE(SUM(InvoiceLines[SalePrice]),Clients[ClientType]="Dealer")
As you can see (as you would in Excel), you can combine functions—even complex filtered functions—in a single metric to deliver powerful analysis. Using this measure in a simple table displaying sales by make produces the results shown in Figure 12-12.
A370912_2_En_12_Fig12_HTML.jpg
Figure 12-12.
Using multiple filters in a measure
Now that you have learned how to create filtered measures, you have mastered the building blocks of an extremely powerful technique that you can adapt and extend in your own data models.

Calculating Percentages of Totals

The filters that you have applied up until now in this chapter merely delivered subsets of data. Sometimes you need filters to do the opposite, and apply a calculation to an entire dataset. In other words, you need filters that remove filters. This is often because calculating a total means telling DAX to aggregate a column without applying any of the filtering by row that would normally be applied. In other words, you need to prevent the automatic filters that have proved so useful thus far.

A Simple Percentage

Imagine a table where you want to calculate the percentage of a total that each row represents. This could be the total of sales by make, for instance. Here you need to simply divide the sales by the total sales. The complete formula is in step 18, should you need it.
  1. 1.
    Click the InvoiceLines table in the Fields list.
     
  2. 2.
    In the Modeling ribbon, click the New Measure button.
     
  3. 3.
    In the formula bar, replace Measure with MakePercentage.
     
  4. 4.
    To the right of the equals sign, enter (or select) DIVIDE(.
     
  5. 5.
    Enter (or select) SUM(.
     
  6. 6.
    Select the InvoiceLines[SalePrice] field.
     
  7. 7.
    Add a right parenthesis. This will terminate the SUM() function.
     
  8. 8.
    Enter a comma.
     
  9. 9.
    Enter (or select) CALCULATE(.
     
  10. 10.
    Enter (or select) SUM(.
     
  11. 11.
    Select the InvoiceLines[SalePrice] field.
     
  12. 12.
    Add a right parenthesis. This will terminate the SUM() function.
     
  13. 13.
    Enter a comma. This tells the CALCULATE() function that you are about to add the filters.
     
  14. 14.
    Enter (or select) ALL(.
     
  15. 15.
    Select the Stock[Make] field.
     
  16. 16.
    Add a right parenthesis. This will terminate the ALL() function.
     
  17. 17.
    Add a right parenthesis. This will terminate the CALCULATE() function.
     
  18. 18.
    Add a right parenthesis. This will terminate the DIVIDE() function. The formula should now read as follows:
    MakePercentage = DIVIDE(SUM(InvoiceLines[SalePrice]), CALCULATE(SUM(InvoiceLines[SalePrice]), ALL(Stock[Make])))
     
  19. 19.
    Format the new column as a percentage.
     
If you create a simple table of sales per make and add this new measure, it should look like Figure 12-13.
A370912_2_En_12_Fig13_HTML.jpg
Figure 12-13.
Using the ALL() function to calculate a percentage per attribute
This formula and the concept behind it probably seem a little peculiar. So let me explain the ALL() function in greater detail. In essence, the ALL() function says, “Remove all the filters concerning any specified fields.” Consequently, in this example, the make is not filtered when calculating the total sales. This means that the unfiltered total can now be calculated—and so can the percentage of each make relative to this grand total.
It is important to note that the ALL() function only removes filters for the fields that you have specified. For instance, look at Figure 12-14, which shows a matrix for the sales and the percentage by make for two colors.
A370912_2_En_12_Fig14_HTML.jpg
Figure 12-14.
The ALL() function lets all other filters be applied
You can see here that the measure MakePercentage is correctly applied independently from sales for 2014, 2015, and the grand total. This is because all other filters (the year in this case) are applied as you have come to expect with Power BI Desktop; only the make is not filtered when calculating the total sales.

Removing Multiple Filter Elements

If your visualization is more complex than the simple example that you just saw, then you have to craft your measures appropriately to handle any complexity. For instance, take the case where you want to see sales by make and color, and display the percentage of each row compared to the total. You need to calculate a total that discards the filters for make and color so that DAX can arrive at the correct figure for the overall total. Here is the formula that can do this:
MakeAndColorPercentage = DIVIDE(SUM(InvoiceLines[SalePrice]), CALCULATE(SUM(InvoiceLines[SalePrice]), ALL(Stock[Make]), ALL(Colors[Color])))
Since this code snippet is only an extension of the previous one, I have not explained how to construct it in detail. All you have to do is follow the steps from the previous example and add a second filter to the second CALCULATE() function (the one that returns the grand total of sales). As you saw earlier in this chapter, the CALCULATE() function can take multiple filter parameters. It follows that it can also take multiple “unfilter” parameters, as it is doing here. The key is in the following part of the measure:
ALL(Stock[Make]), ALL(Colors[Color])
This piece of DAX is simply saying, “Don’t apply any make or color filters when calculating.” The consequence is that this measure now calculates the total sales whatever the make or color. This then becomes the basis for the percentage calculation, as you can see in Figure 12-15.
A370912_2_En_12_Fig15_HTML.jpg
Figure 12-15.
Using the ALL() function to calculate a percentage per attribute
Admittedly, preparing highly specific measures like those that you have seen in the last few pages can take a few minutes. Clearly, these measures are tightly linked to the data that you are displaying in the visuals that use them. However, the ability to compose highly focused metrics like these is often key to using your dashboards to highlight the insights that you want to deliver.

Visual Totals

Users (meaning the target audience for your reports and dashboards) do not like anomalies or apparent contradictions. So you have to be sure that the data that they see is visually coherent. This is especially true when displaying tables and matrices with subtotals and grand totals where you want percentage totals to reflect the figures shown and not include any records that have been removed by the filter.
One technique that can help you here is the ALLSELECTED() function . This only applies any filters that have been added (either at the report, page, or visualization level, or as slicers or cross-filters from other visuals) without your having to specify the fields that you do not want to filter, as you did in the previous examples.
SalesPercentage is a measure that uses the ALLSELECTED() function as the filter for the CALCULATE() function that returns the total much like you did earlier:
SalesPercentage = DIVIDE(SUM(InvoiceLines[SalePrice]), CALCULATE(SUM(InvoiceLines[SalePrice]), ALLSELECTED()))
If you look at Figure 12-16, you see that the subtotals for the sales percentage (and indeed the grand total) are accurate, despite the fact that the country (USA) is selected in a slicer and three colors in a filter.
A370912_2_En_12_Fig16_HTML.jpg
Figure 12-16.
Using the ALLSELECTED() function to calculate a percentage per attribute per group
The ALLSELECTED() function says to DAX, “Don’t filter on any filters applied by the user, whatever the technique used to apply them.” This can make creating percentage totals much easier, as this function removes the need to create highly specific measures that are tied to specific levels of totals and subtototals.

The ALLEXCEPT() Function

In practice, you could find yourself having to write extremely targeted measures that need to remove filters from all the elements in a calculation except one or two. So, to save you from having to write long lists of ALL() functions, you can say “All but” a field using the ALLEXCEPT() function.
As an example of this (although it is extremely simple), suppose that you want to see the percentages of sales grouped by a subclassification. You know that you want to have Make as the main grouping element, but then you might want to use Color, Client, or even Model as the subgroup. So to save you from having to write a measure specifically for each of these combinations, you can write the following:
AllButMakePercentage = DIVIDE(SUM(InvoiceLines[SalePrice]), CALCULATE(SUM(InvoiceLines[SalePrice]), ALLEXCEPT(Stock, Stock[Make])))
If you use this measure in a matrix where Make is the leftmost column , you can then add subgroups using any other field to get the kind of output that is shown in Figure 12-17.
A370912_2_En_12_Fig17_HTML.jpg
Figure 12-17.
Using the ALLEXCEPT() function to calculate a percentage per attribute per group
In this example, other filters (color here) are applied, but not make. So you are displaying the percentage for each color compared to the aggregate total for the make.
Note
ALLEXCEPT() does what it says and removes all filters except the one that you specify. This can have the effect of preventing other filters from working as you expect.

Filtering on Measures

The CALCULATE() function is without a doubt one of the most powerful functions that you will use in DAX. However, there are a few things that it cannot do. One of these is to filter data by comparing to a measure rather than to a column. If you cast your mind back to the examples where CALCULATE() was applied, you will remember that a data column or a calculated column was used every time that a comparison (text-based or numeric) was invoked. Indeed, if you try to use CALCULATE() with a measure rather than a column, you will get an error.
Fortunately, DAX has a solution to this conundrum, which is to use the FILTER() function . You may well wonder what the differences are between FILTER() and CALCULATE(). Well, at its simplest, FILTER() can use measures as part of a comparison, whereas CALCULATE() must use columns—or calculated columns. Also, FILTER() must use an iterator function (such as SUMX()) rather than a simple aggregation function to produce a correct result.
Let’s see this in action. Suppose that you want to isolate sales where the ratio of net margin is over 50%. Fortunately, you have a measure—RatioNetMargin—that calculates the percentage. The following explains how you can use this measure in a filter so that you can display these lucrative sales. The complete formula is in step 16.
  1. 1.
    Click the InvoiceLines table in the Fields list.
     
  2. 2.
    In the Modeling ribbon, click the New Measure button.
     
  3. 3.
    In the formula bar, replace Measure with HighNetMarginSales.
     
  4. 4.
    To the right of the equals sign, enter (or select) CALCULATE(.
     
  5. 5.
    Enter (or select) SUM(.
     
  6. 6.
    Select the InvoiceLines[SalePrice] field.
     
  7. 7.
    Add a right parenthesis. This will terminate the SUM() function.
     
  8. 8.
    Enter a comma. This tells the CALCULATE() function that you are about to add the filters.
     
  9. 9.
    Enter (or select) FILTER(.
     
  10. 10.
    Select the InvoiceLines table. This is the table to filter.
     
  11. 11.
    Enter a comma. This tells the FILTER() function that you are about to enter the filter criteria.
     
  12. 12.
    Enter (or select) the column [RatioNetMargin].
     
  13. 13.
    Enter the greater than symbol: >.
     
  14. 14.
    Enter the figure 0.5.
     
  15. 15.
    Add a right parenthesis. This will terminate the FILTER() function.
     
  16. 16.
    Add a right parenthesis. This will terminate the CALCULATE() function. The formula should now read
     
HighNetMarginSales = CALCULATE(SUM(InvoiceLines[SalePrice]),FILTER(InvoiceLines, [RatioNetMargin]>0.5))
If you use this measure in a table of sales by make and model, you should see something like Figure 12-18.
A370912_2_En_12_Fig18_HTML.jpg
Figure 12-18.
Applying a filter to a measure
In this example, you filtered data on a measure (RatioNetMargin) rather than a column. Be aware, however, that the FILTER() function can be slow when applied to large datasets.

Displaying Rank

DAX can do so much when it comes to preparing metrics for BI delivery that it is hard to know exactly what you need and when. The final example in this short tour of DAX measures explains how to rank sales by make. I realize that you can do this just by sorting records, but should you need a clear and unequivocal indicator of ranking, then here is how it can be done-and the formula is directly available in step 16:
  1. 1.
    Click the InvoiceLines table in the Fields list.
     
  2. 2.
    In the Modeling ribbon, click the New Measure button.
     
  3. 3.
    In the formula bar, replace Measure with SalesRankByMake.
     
  4. 4.
    To the right of the equals sign, enter (or select) RANKX(.
     
  5. 5.
    Enter (or select) ALL(.
     
  6. 6.
    Select the Stock[Make] field.
     
  7. 7.
    Add a right parenthesis. This will terminate the ALL() function.
     
  8. 8.
    Enter a comma. This tells the RANK() function that you are going to enter the calculation of how to order the data.
     
  9. 9.
    Enter (or select) SUMX(.
     
  10. 10.
    Enter (or select) RELATEDTABLE(.
     
  11. 11.
    Select the InvoiceLines table. This is the table where the data is to be sourced.
     
  12. 12.
    Add a right parenthesis. This will terminate the RELATEDTABLE() function.
     
  13. 13.
    Enter a comma. This tells the RELATEDTABLE() function that you are about to enter the field to use.
     
  14. 14.
    Enter (or select) [SalePrice].
     
  15. 15.
    Add a right parenthesis. This will terminate the SUMX() function.
     
  16. 16.
    Add a right parenthesis. This will terminate the RANKX() function. The formula should now read
     
SalesRankByMake = RANKX(ALL(Stock[Make]),SUMX(RELATEDTABLE (InvoiceLines), [SalePrice]))
If you apply this measure to a simple table that lists the makes sold (in 2014, for instance) and then sort by the SalesRankByMake field, you will see something like Figure 12-19.
A370912_2_En_12_Fig19_HTML.jpg
Figure 12-19.
Using the RANKX() function to classify data
As its name implies, RANKX() ranks the first field using the order returned by the descending output of the second field.

A Few Comments and Notes on Using Measures

Measures are an immense subject. The breadth and depth of the calculations that can be delivered using DAX are little short of astounding. Consequently, it is impossible in an introductory chapter on measures to do anything other than give you a taste of what can be done and provide a few useful starter functions for you to adapt to your own requirements.
As you move on with DAX, a few things might help you on your way. The first concerns the use of calculated columns. Sometimes they are such an easy solution that it is a shame not to create them. However, they are stored in the table and do take up space. This means more space on disk and more space in memory. This is particularly true for a table containing tens of millions of rows. Measures, on the other hand, are only calculated at run time, and so they take up virtually no space. So, if you are considering creating many calculated columns, perhaps some of them could become measures instead.

Calculation Options

I imagine that you have not had to worry about recalculation of Power BI Desktop workbooks if you have been using relatively small datasets like the sample data for this book. If you are using vast amounts of data (after all, this is what Power BI Desktop was designed for), however, then recalculation could become a subject that you need to master.
By default, Power BI Desktop recalculates all calculated columns and measures when there is a change in the dataset. These are the main operations that can trigger a recalculation:
  • Data from an external data source (of any kind) has been updated.
  • Data from an external data source has been filtered.
  • You have changed the name of a table or column.
  • You have added, modified, or deleted relationships between tables.
  • You have altered any formula for a calculated column or a measure.
  • You have added new calculated columns or measures.
More generally, if you want to be sure that your data is up to date, you should probably update the data. You can do this by clicking the Refresh button in the Home ribbon.

Conclusion

In this chapter, you took a first look at one of the most powerful features in DAX: measures. These let you develop custom calculations for the Power BI Desktop data model. You then use these metrics in your visuals to deliver specific insights based on your data.
First, you saw how to apply iterator functions so that you can apply a calculation to a set of rows and return an aggregation, be it a sum, average, or any other available aggregate function. Then you saw how to apply specific filters to your calculations. Finally, you saw how to prevent filters from being applied so that you can display percentages and calculate advanced ratios.
This chapter was only a brief introduction to measures in DAX. Yet I hope that it has whetted your appetite and that you will now feel empowered to continue, and consequently to develop the analyses and metrics that you need for your own data.
It will soon be time to start applying these measures to a range of visualizations in Power BI Desktop. However, before then let’s take a look at one final fundamental element of the data model that you will need to set up before you can extract real value from your data. The remaining piece of the puzzle is adding time intelligence, and this is the subject of the next chapter.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.13.180