Foreword |
|
xvii | |
Introduction to the second edition |
|
xx | |
Introduction to the first edition |
|
xxi | |
Chapter 1 What is DAX? |
|
1 | (16) |
|
Understanding the data model |
|
|
1 | (4) |
|
Understanding the direction of a relationship |
|
|
3 | (2) |
|
|
5 | (4) |
|
|
5 | (2) |
|
Excel and DAX: Two functional languages |
|
|
7 | (1) |
|
|
8 | (1) |
|
|
8 | (1) |
|
|
9 | (3) |
|
|
9 | (1) |
|
DAX is a functional language |
|
|
10 | (1) |
|
DAX as a programming and querying language |
|
|
10 | (1) |
|
Subqueries and conditions in DAX and SQL |
|
|
11 | (1) |
|
|
12 | (2) |
|
Multidimensional versus Tabular |
|
|
12 | (1) |
|
DAX as a programming and querying language |
|
|
12 | (1) |
|
|
13 | (1) |
|
|
14 | (1) |
|
|
14 | (3) |
Chapter 2 Introducing DAX |
|
17 | (40) |
|
Understanding DAX calculations |
|
|
17 | (8) |
|
|
19 | (4) |
|
|
23 | (1) |
|
|
24 | (1) |
|
|
24 | (1) |
|
Understanding calculated columns and measures |
|
|
25 | (5) |
|
|
25 | (1) |
|
|
26 | (4) |
|
|
30 | (1) |
|
Handling errors in DAX expressions |
|
|
31 | (8) |
|
|
31 | (1) |
|
Arithmetic operations errors |
|
|
32 | (3) |
|
|
35 | (3) |
|
|
38 | (1) |
|
|
39 | (3) |
|
Introducing aggregators and iterators |
|
|
42 | (3) |
|
Using common DAX functions |
|
|
45 | (10) |
|
|
45 | (1) |
|
|
46 | (2) |
|
|
48 | (1) |
|
|
49 | (1) |
|
|
50 | (1) |
|
|
50 | (1) |
|
|
51 | (1) |
|
|
52 | (1) |
|
|
53 | (2) |
|
|
55 | (2) |
Chapter 3 Using basic table functions |
|
57 | (22) |
|
Introducing table functions |
|
|
57 | (2) |
|
Introducing EVALUATE syntax |
|
|
59 | (2) |
|
|
61 | (2) |
|
Introducing ALL and ALLEXCEPT |
|
|
63 | (5) |
|
Understanding VALUES, DISTINCT and the blank row |
|
|
68 | (4) |
|
Using tables as scalar values |
|
|
72 | (3) |
|
|
75 | (2) |
|
|
77 | (2) |
Chapter 4 Understanding evaluation contexts |
|
79 | (36) |
|
Introducing evaluation contexts |
|
|
80 | (8) |
|
Understanding filter contexts |
|
|
80 | (5) |
|
Understanding the row context |
|
|
85 | (3) |
|
Testing your understanding of evaluation contexts |
|
|
88 | (2) |
|
Using SUM in a calculated column |
|
|
88 | (1) |
|
Using columns in a measure |
|
|
89 | (1) |
|
Using the row context with iterators |
|
|
90 | (8) |
|
Nested row contexts on different tables |
|
|
91 | (1) |
|
Nested row contexts on the same table |
|
|
92 | (5) |
|
Using the EARLIER function |
|
|
97 | (1) |
|
Understanding FILTER, ALL, and context interactions |
|
|
98 | (3) |
|
Working with several tables |
|
|
101 | (8) |
|
Row contexts and relationships |
|
|
102 | (4) |
|
Filter context and relationships |
|
|
106 | (3) |
|
Using DISTINCT and SUMMARIZE in filter contexts |
|
|
109 | (4) |
|
|
113 | (2) |
Chapter 5 Understanding CALCULATE and CALCULATETABLE |
|
115 | (60) |
|
Introducing CALCULATE and CALCULATETABLE |
|
|
115 | (33) |
|
|
115 | (4) |
|
|
119 | (5) |
|
Using CALCULATE to compute percentages |
|
|
124 | (11) |
|
|
135 | (3) |
|
Filtering a single column |
|
|
138 | (2) |
|
Filtering with complex conditions |
|
|
140 | (4) |
|
Evaluation order in CALCULATE |
|
|
144 | (4) |
|
Understanding context transition |
|
|
148 | (13) |
|
Row context and filter context recap |
|
|
148 | (3) |
|
Introducing context transition |
|
|
151 | (3) |
|
Context transition in calculated columns |
|
|
154 | (3) |
|
Context transition with measures |
|
|
157 | (4) |
|
Understanding circular dependencies |
|
|
161 | (3) |
|
|
164 | (8) |
|
Understanding USERELATIONSHIP |
|
|
164 | (4) |
|
Understanding CROSSFILTER |
|
|
168 | (1) |
|
Understanding KEEPFILTERS |
|
|
168 | (1) |
|
Understanding ALL in CALCULATE |
|
|
169 | (2) |
|
Introducing ALL and ALLSELECTED with no parameters |
|
|
171 | (1) |
|
|
172 | (3) |
Chapter 6 Variables |
|
175 | (12) |
|
|
175 | (2) |
|
Understanding that variables are constant |
|
|
177 | (1) |
|
Understanding the scope of variables |
|
|
178 | (3) |
|
|
181 | (1) |
|
Understanding lazy evaluation |
|
|
182 | (1) |
|
Common patterns using variables |
|
|
183 | (2) |
|
|
185 | (2) |
Chapter 7 Working with iterators and with CALCULATE |
|
187 | (30) |
|
|
187 | (12) |
|
Understanding iterator cardinality |
|
|
188 | (2) |
|
Leveraging context transition in iterators |
|
|
190 | (4) |
|
|
194 | (2) |
|
Iterators returning tables |
|
|
196 | (3) |
|
Solving common scenarios with iterators |
|
|
199 | (16) |
|
Computing averages and moving averages |
|
|
199 | (4) |
|
|
203 | (8) |
|
Changing calculation granularity |
|
|
211 | (4) |
|
|
215 | (2) |
Chapter 8 Time intelligence calculations |
|
217 | (62) |
|
Introducing time intelligence |
|
|
217 | (3) |
|
Automatic Date/Time in Power 81 |
|
|
218 | (1) |
|
Automatic date columns in Power Pivot for Excel |
|
|
219 | (1) |
|
Date table template in Power Pivot for Excel |
|
|
220 | (1) |
|
|
220 | (8) |
|
Using CALENDAR and CALENDARAUTO |
|
|
222 | (2) |
|
Working with multiple dates |
|
|
224 | (1) |
|
Handling multiple relationships to the Date table |
|
|
224 | (2) |
|
Handling multiple date tables |
|
|
226 | (2) |
|
Understanding basic time intelligence calculations |
|
|
228 | (5) |
|
|
232 | (1) |
|
Introducing basic time intelligence functions |
|
|
233 | (13) |
|
Using year-to-date, quarter-to-date, and month-to-date |
|
|
235 | (2) |
|
Computing time periods from prior periods |
|
|
237 | (2) |
|
Mixing time intelligence functions |
|
|
239 | (2) |
|
Computing a difference over previous periods |
|
|
241 | (2) |
|
Computing a moving annual total |
|
|
243 | (2) |
|
Using the right call order for nested time intelligence functions |
|
|
245 | (1) |
|
Understanding semi-additive calculations |
|
|
246 | (12) |
|
Using LASTDATE and LASTNONBLANK |
|
|
248 | (6) |
|
Working with opening and closing balances |
|
|
254 | (4) |
|
Understanding advanced time intelligence calculations |
|
|
258 | (14) |
|
Understanding periods to date |
|
|
259 | (3) |
|
|
262 | (7) |
|
Understanding FIRSTDATE, LASTDATE, FIRSTNONBLANK, and LASTNONBLANK |
|
|
269 | (2) |
|
Using drillthrough with time intelligence |
|
|
271 | (1) |
|
Working with custom calendars |
|
|
272 | (5) |
|
|
272 | (4) |
|
Custom year-to-date, quarter-to-date, and month-to-date |
|
|
276 | (1) |
|
|
277 | (2) |
Chapter 9 Calculation groups |
|
279 | (34) |
|
Introducing calculation groups |
|
|
279 | (2) |
|
Creating calculation groups |
|
|
281 | (7) |
|
Understanding calculation groups |
|
|
288 | (18) |
|
Understanding calculation item application |
|
|
291 | (8) |
|
Understanding calculation group precedence |
|
|
299 | (5) |
|
Including and excluding measures from calculation items |
|
|
304 | (2) |
|
Understanding sideways recursion |
|
|
306 | (5) |
|
|
311 | (1) |
|
|
311 | (2) |
Chapter 10 Working with the filter context |
|
313 | (32) |
|
Using HASONEVALUE and SELECTEDVALUE |
|
|
314 | (5) |
|
Introducing ISFILTERED and ISCROSSFILTERED |
|
|
319 | (3) |
|
Understanding differences between VALUES and FILTERS |
|
|
322 | (2) |
|
Understanding the difference between ALLEXCEPT and ALL/VALUES |
|
|
324 | (4) |
|
Using ALL to avoid context transition |
|
|
328 | (2) |
|
|
330 | (2) |
|
Introducing data lineage and TREATAS |
|
|
332 | (4) |
|
Understanding arbitrarily shaped filters |
|
|
336 | (7) |
|
|
343 | (2) |
Chapter 11 Handling hierarchies |
|
345 | (18) |
|
Computing percentages over hierarchies |
|
|
345 | (5) |
|
Handling parent/child hierarchies |
|
|
350 | (12) |
|
|
362 | (1) |
Chapter 12 Working with tables |
|
363 | (32) |
|
|
363 | (2) |
|
|
365 | (16) |
|
|
366 | (3) |
|
|
369 | (3) |
|
|
372 | (2) |
|
|
374 | (4) |
|
|
378 | (1) |
|
|
379 | (2) |
|
|
381 | (9) |
|
Implementing OR conditions |
|
|
381 | (3) |
|
Narrowing sales computation to the first year's customers |
|
|
384 | (2) |
|
|
386 | (2) |
|
Reusing table expressions with DETAILROWS |
|
|
388 | (2) |
|
Creating calculated tables |
|
|
390 | (4) |
|
|
390 | (1) |
|
Creating static tables with ROW |
|
|
391 | (1) |
|
Creating static tables with DATATABLE |
|
|
392 | (1) |
|
|
393 | (1) |
|
|
394 | (1) |
Chapter 13 Authoring queries |
|
395 | (42) |
|
|
395 | (1) |
|
|
396 | (4) |
|
Introducing the EVALUATE syntax |
|
|
396 | (1) |
|
|
397 | (2) |
|
|
399 | (1) |
|
Implementing common DAX query patterns |
|
|
400 | (29) |
|
Using ROW to test measures |
|
|
400 | (1) |
|
|
401 | (2) |
|
|
403 | (6) |
|
|
409 | (6) |
|
Using GENERATE and GENERATEALL |
|
|
415 | (3) |
|
|
418 | (2) |
|
|
420 | (1) |
|
|
421 | (1) |
|
|
421 | (3) |
|
Using NATURALINNERJOIN and NATURALLEFTOUTERJOIN |
|
|
424 | (2) |
|
Using SUBSTITUTE WITHINDEX |
|
|
426 | (2) |
|
|
428 | (1) |
|
Understanding the auto-exists behavior in DAX queries |
|
|
429 | (6) |
|
|
435 | (2) |
Chapter 14 Advanced DAX concepts |
|
437 | (34) |
|
Introducing expanded tables |
|
|
437 | (7) |
|
|
441 | (2) |
|
Using RELATED in calculated columns |
|
|
443 | (1) |
|
Understanding the difference between table filters and column filters |
|
|
444 | (12) |
|
Using table filters in measures |
|
|
447 | (4) |
|
Understanding active relationships |
|
|
451 | (2) |
|
Difference between table expansion and filtering |
|
|
453 | (2) |
|
Context transition in expanded tables |
|
|
455 | (1) |
|
Understanding ALLSELECTED and shadow filter contexts |
|
|
456 | (7) |
|
Introducing shadow filter contexts |
|
|
457 | (4) |
|
ALLSELECTED returns the iterated rows |
|
|
461 | (2) |
|
ALLSELECTED without parameters |
|
|
463 | (1) |
|
The ALL* family of functions |
|
|
463 | (3) |
|
|
465 | (1) |
|
|
466 | (1) |
|
|
466 | (1) |
|
|
466 | (1) |
|
|
466 | (1) |
|
Understanding data lineage |
|
|
466 | (3) |
|
|
469 | (2) |
Chapter 15 Advanced relationships |
|
471 | (48) |
|
Implementing calculated physical relationships |
|
|
471 | (9) |
|
Computing multiple-column relationships |
|
|
471 | (3) |
|
Implementing relationships based on ranges |
|
|
474 | (2) |
|
Understanding circular dependency in calculated physical relationships |
|
|
476 | (4) |
|
Implementing virtual relationships |
|
|
480 | (8) |
|
Transferring filters in DAX |
|
|
480 | (2) |
|
Transferring a filter using TREATAS |
|
|
482 | (1) |
|
Transferring a filter using INTERSECT |
|
|
483 | (1) |
|
Transferring a filter using FILTER |
|
|
484 | (1) |
|
Implementing dynamic segmentation using virtual relationships |
|
|
485 | (3) |
|
Understanding physical relationships in DAX |
|
|
488 | (3) |
|
Using bidirectional cross-filters |
|
|
491 | (2) |
|
Understanding one-to-many relationships |
|
|
493 | (1) |
|
Understanding one-to-one relationships |
|
|
493 | (1) |
|
Understanding many-to-many relationships |
|
|
494 | (12) |
|
Implementing many-to-many using a bridge table |
|
|
494 | (6) |
|
Implementing many-to-many using a common dimension |
|
|
500 | (4) |
|
Implementing many-to-many using MMR weak relationships |
|
|
504 | (2) |
|
Choosing the right type of relationships |
|
|
506 | (1) |
|
|
507 | (5) |
|
Managing ambiguity in relationships |
|
|
512 | (5) |
|
Understanding ambiguity in active relationships |
|
|
514 | (1) |
|
Solving ambiguity in non-active relationships |
|
|
515 | (2) |
|
|
517 | (2) |
Chapter 16 Advanced calculations in DAX |
|
519 | (26) |
|
Computing the working days between two dates |
|
|
519 | (8) |
|
Showing budget and sales together |
|
|
527 | (3) |
|
Computing same-store sales |
|
|
530 | (6) |
|
Numbering sequences of events |
|
|
536 | (3) |
|
Computing previous year sales up to last date of sales |
|
|
539 | (5) |
|
|
544 | (1) |
Chapter 17 The DAX engines |
|
545 | (34) |
|
Understanding the architecture of the DAX engines |
|
|
545 | (5) |
|
Introducing the formula engine |
|
|
547 | (1) |
|
Introducing the storage engine |
|
|
547 | (1) |
|
Introducing the VertiPaq (in-memory) storage engine |
|
|
548 | (1) |
|
Introducing the DirectQuery storage engine |
|
|
549 | (1) |
|
Understanding data refresh |
|
|
549 | (1) |
|
Understanding the VertiPaq storage engine |
|
|
550 | (15) |
|
Introducing columnar databases |
|
|
550 | (3) |
|
Understanding VertiPaq compression |
|
|
553 | (9) |
|
Understanding segmentation and partitioning |
|
|
562 | (1) |
|
Using Dynamic Management Views |
|
|
563 | (2) |
|
Understanding the use of relationships in VertiPaq |
|
|
565 | (3) |
|
Introducing materialization |
|
|
568 | (3) |
|
|
571 | (2) |
|
Choosing hardware for VertiPaq |
|
|
573 | (4) |
|
Hardware choice as an option |
|
|
573 | (1) |
|
|
574 | (1) |
|
|
574 | (1) |
|
|
575 | (1) |
|
|
576 | (1) |
|
|
576 | (1) |
|
|
576 | (1) |
|
Best practices in hardware selection |
|
|
577 | (1) |
|
|
577 | (2) |
Chapter 18 Optimizing VertiPaq |
|
579 | (30) |
|
Gathering information about the data model |
|
|
579 | (5) |
|
|
584 | (7) |
|
|
591 | (1) |
|
|
592 | (3) |
|
|
595 | (4) |
|
Optimizing complex filters with Boolean calculated columns |
|
|
597 | (2) |
|
Processing of calculated columns |
|
|
599 | (1) |
|
Choosing the right columns to store |
|
|
599 | (3) |
|
Optimizing column storage |
|
|
602 | (2) |
|
Using column split optimization |
|
|
602 | (1) |
|
Optimizing high-cardinality columns |
|
|
603 | (1) |
|
Disabling attribute hierarchies |
|
|
604 | (1) |
|
Optimizing drill-through attributes |
|
|
604 | (1) |
|
Managing VertiPaq Aggregations |
|
|
604 | (3) |
|
|
607 | (2) |
Chapter 19 Analyzing DAX query plans |
|
609 | (48) |
|
|
609 | (3) |
|
Introducing DAX query plans |
|
|
612 | (5) |
|
|
613 | (1) |
|
Introducing logical query plans |
|
|
614 | (1) |
|
Introducing physical query plans |
|
|
614 | (2) |
|
Introducing storage engine queries |
|
|
616 | (1) |
|
Capturing profiling information |
|
|
617 | (7) |
|
|
617 | (3) |
|
Using the SQL Server Profiler |
|
|
620 | (4) |
|
Reading VertiPaq storage engine queries |
|
|
624 | (21) |
|
|
624 | (8) |
|
|
632 | (2) |
|
Understanding DISTINCTCOUNT internals |
|
|
634 | (1) |
|
Understanding parallelism and datacache |
|
|
635 | (2) |
|
Understanding the VertiPaq cache |
|
|
637 | (3) |
|
Understanding CallbackDatalD |
|
|
640 | (5) |
|
Reading DirectQuery storage engine queries |
|
|
645 | (4) |
|
Analyzing composite models |
|
|
646 | (1) |
|
Using aggregations in the data model |
|
|
647 | (2) |
|
|
649 | (6) |
|
|
655 | (2) |
Chapter 20 Optimizing DAX |
|
657 | (120) |
|
Defining optimization strategies |
|
|
658 | (10) |
|
Identifying a single DAX expression to optimize |
|
|
658 | (3) |
|
Creating a reproduction query |
|
|
661 | (3) |
|
Analyzing server timings and query plan information |
|
|
664 | (3) |
|
Identifying bottlenecks in the storage engine or formula engine |
|
|
667 | (1) |
|
Implementing changes and rerunning the test query |
|
|
668 | (1) |
|
Optimizing bottlenecks in DAX expressions |
|
|
668 | (41) |
|
Optimizing filter conditions |
|
|
668 | (4) |
|
Optimizing context transitions |
|
|
672 | (6) |
|
|
678 | (12) |
|
Reducing the impact of CallbockDatoID |
|
|
690 | (3) |
|
Optimizing nested iterators |
|
|
693 | (6) |
|
Avoiding table filters for DISTINCTCOUNT |
|
|
699 | (5) |
|
Avoiding multiple evaluations by using variables |
|
|
704 | (5) |
|
|
709 | (68) |
Index |
|
777 | |