- •Contents at a glance
- •Contents
- •Introduction
- •Who this book is for
- •Assumptions about you
- •Organization of this book
- •Conventions
- •About the companion content
- •Acknowledgments
- •Errata and book support
- •We want to hear from you
- •Stay in touch
- •Chapter 1. Introduction to data modeling
- •Working with a single table
- •Introducing the data model
- •Introducing star schemas
- •Understanding the importance of naming objects
- •Conclusions
- •Chapter 2. Using header/detail tables
- •Introducing header/detail
- •Aggregating values from the header
- •Flattening header/detail
- •Conclusions
- •Chapter 3. Using multiple fact tables
- •Using denormalized fact tables
- •Filtering across dimensions
- •Understanding model ambiguity
- •Using orders and invoices
- •Calculating the total invoiced for the customer
- •Calculating the number of invoices that include the given order of the given customer
- •Calculating the amount of the order, if invoiced
- •Conclusions
- •Chapter 4. Working with date and time
- •Creating a date dimension
- •Understanding automatic time dimensions
- •Automatic time grouping in Excel
- •Automatic time grouping in Power BI Desktop
- •Using multiple date dimensions
- •Handling date and time
- •Time-intelligence calculations
- •Handling fiscal calendars
- •Computing with working days
- •Working days in a single country or region
- •Working with multiple countries or regions
- •Handling special periods of the year
- •Using non-overlapping periods
- •Periods relative to today
- •Using overlapping periods
- •Working with weekly calendars
- •Conclusions
- •Chapter 5. Tracking historical attributes
- •Introducing slowly changing dimensions
- •Using slowly changing dimensions
- •Loading slowly changing dimensions
- •Fixing granularity in the dimension
- •Fixing granularity in the fact table
- •Rapidly changing dimensions
- •Choosing the right modeling technique
- •Conclusions
- •Chapter 6. Using snapshots
- •Using data that you cannot aggregate over time
- •Aggregating snapshots
- •Understanding derived snapshots
- •Understanding the transition matrix
- •Conclusions
- •Chapter 7. Analyzing date and time intervals
- •Introduction to temporal data
- •Aggregating with simple intervals
- •Intervals crossing dates
- •Modeling working shifts and time shifting
- •Analyzing active events
- •Mixing different durations
- •Conclusions
- •Chapter 8. Many-to-many relationships
- •Introducing many-to-many relationships
- •Understanding the bidirectional pattern
- •Understanding non-additivity
- •Cascading many-to-many
- •Temporal many-to-many
- •Reallocating factors and percentages
- •Materializing many-to-many
- •Using the fact tables as a bridge
- •Performance considerations
- •Conclusions
- •Chapter 9. Working with different granularity
- •Introduction to granularity
- •Relationships at different granularity
- •Analyzing budget data
- •Using DAX code to move filters
- •Filtering through relationships
- •Hiding values at the wrong granularity
- •Allocating values at a higher granularity
- •Conclusions
- •Chapter 10. Segmentation data models
- •Computing multiple-column relationships
- •Computing static segmentation
- •Using dynamic segmentation
- •Understanding the power of calculated columns: ABC analysis
- •Conclusions
- •Chapter 11. Working with multiple currencies
- •Understanding different scenarios
- •Multiple source currencies, single reporting currency
- •Single source currency, multiple reporting currencies
- •Multiple source currencies, multiple reporting currencies
- •Conclusions
- •Appendix A. Data modeling 101
- •Tables
- •Data types
- •Relationships
- •Filtering and cross-filtering
- •Different types of models
- •Star schema
- •Snowflake schema
- •Models with bridge tables
- •Measures and additivity
- •Additive measures
- •Non-additive measures
- •Semi-additive measures
- •Index
- •Code Snippets
if an order was included in an invoice but not completely invoiced? There might be several reasons for this, and the calculations are even more complex. We will focus on that scenario later. For now, let’s solve these first three calculations.
Calculating the total invoiced for the customer
The first calculation is the one that exists right now. Because the amount invoiced does not depend on the order, you simply sum the invoice amounts and produce a result. The major drawback of this solution is that the filter on the order number is not effective against the invoices, so you will always report the amount invoiced to the customer, regardless of the order number.
Calculating the number of invoices that include the given order of the given customer
To compute the second calculation, you must explicitly force the filter on the orders to work on the invoices. This can be performed by using the bidirectional pattern, as in the following code:
Click here to view code image
Amount Invoiced Filtered by Orders := CALCULATE (
[Amount Invoiced],
CROSSFILTER ( Orders[Invoice], Invoices[Invoice]
)
The result of this calculation is that [Amount Invoiced] is computed for only the invoices that are present in the current selection of orders. You can see the resulting PivotTable in Figure 3-18.
FIGURE 3-18 Moving the filter from orders to invoices changes the result.
Calculating the amount of the order, if invoiced
The last measure, as expected, is non-additive. In fact, because it reports the total invoiced for each order, it will typically show a much higher value than the order amount. You might recall this behavior from the previous chapter. Because we are aggregating a value from the header table, when we browse using a filter on the detail, the resulting calculation is non-additive.
To make the measure additive, you should check for each order to determine whether it has been invoiced. If so, then the amount invoiced is the amount of the order. Otherwise it is zero. This can be easily done with a calculated column or with a slightly more complex measure, like the following:
Click here to view code image
Amount Invoiced Filtered by Orders := CALCULATE (
SUMX ( Orders,
IF ( NOT ( ISBLANK ( Orders[Invoice] ) ), Or
),
CROSSFILTER ( Orders[Invoice], Invoices[Invoice]
)
This measure works well if an order is always fully invoiced, but otherwise it computes a wrong number because it returns the amount invoiced. An example is shown in Figure 3-19, which reports the same value for the total invoiced and the total ordered, even if we know that the two numbers should be different. This is because we are computing the amount invoiced from the orders instead of from the invoices.
FIGURE 3-19 If an order is not fully invoiced, the last measure shows an incorrect result.
There is no easy way to compute the partial amount of the order invoiced because that information is not there, in the model. In the case of partial invoicing, if you only store for each order the invoice that contains it, you are missing the important value of the amount invoiced. To provide a correct result, you should store this value, too, and use the amount invoiced instead of the amount of the
order in the previous formula.
In addressing this point, we go one step further and build a complete model to solve the scenario. We will build a model that enables you to invoice an order with different invoices and to state, for each pair of invoices and orders, the amount invoiced. The model needs to be a bit more complex. It will involve an additional table that stores the invoice number, the order number, and the amount of the order invoiced. The model is shown in in Figure 3-20.
FIGURE 3-20 This structure models one order with multiple invoices, and one invoice with multiple orders, with the amount invoiced for each order.
The model involves a many-to-many relationship between orders and invoices. A single order can be invoiced with multiple invoices, and, at the same time, a single invoice can contain multiple orders. The amount invoiced for each order is stored in the OrdersInvoices table, so each order can be partially invoiced in different documents.
We will cover in more detail many-to-many handling in Chapter 8, “Many-to- many relationships.” But it is useful, even at this point, to show a correct model to handle invoices and orders. Here, we are deliberately violating the star schema rules to correctly build the model. In fact, the OrdersInvoices table is neither a fact table nor a dimension. It is similar to a fact table because it contains the Amount metric, and it is related to the Invoices dimension. However, it is related to Orders, which is, at the same time, a fact table and a dimension. Technically, the OrdersInvoices table is called a bridge table, because it acts as a bridge between orders and invoices.
Now that the amount invoiced is stored in the bridge table, the formula to