@luquimbo/bi-superpowers 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/.claude-plugin/plugin.json +8 -0
  2. package/.mcp.json +25 -0
  3. package/AGENTS.md +244 -0
  4. package/CHANGELOG.md +265 -0
  5. package/LICENSE +21 -0
  6. package/README.md +211 -0
  7. package/bin/build-plugin.js +30 -0
  8. package/bin/cli.js +1064 -0
  9. package/bin/commands/add.js +533 -0
  10. package/bin/commands/add.test.js +77 -0
  11. package/bin/commands/build-desktop.js +166 -0
  12. package/bin/commands/changelog.js +443 -0
  13. package/bin/commands/diff.js +325 -0
  14. package/bin/commands/lint.js +419 -0
  15. package/bin/commands/lint.test.js +103 -0
  16. package/bin/commands/mcp-setup.js +246 -0
  17. package/bin/commands/pull.js +287 -0
  18. package/bin/commands/pull.test.js +36 -0
  19. package/bin/commands/push.js +231 -0
  20. package/bin/commands/push.test.js +14 -0
  21. package/bin/commands/search.js +344 -0
  22. package/bin/commands/search.test.js +115 -0
  23. package/bin/commands/setup.js +545 -0
  24. package/bin/commands/setup.test.js +46 -0
  25. package/bin/commands/sync-profile.js +405 -0
  26. package/bin/commands/sync-profile.test.js +14 -0
  27. package/bin/commands/sync-source.js +418 -0
  28. package/bin/commands/sync-source.test.js +14 -0
  29. package/bin/commands/watch.js +206 -0
  30. package/bin/lib/generators/claude-plugin.js +266 -0
  31. package/bin/lib/generators/claude-plugin.test.js +110 -0
  32. package/bin/lib/generators/index.js +116 -0
  33. package/bin/lib/generators/shared.js +282 -0
  34. package/bin/lib/licensing/index.js +35 -0
  35. package/bin/lib/licensing/storage.js +364 -0
  36. package/bin/lib/licensing/storage.test.js +55 -0
  37. package/bin/lib/licensing/validator.js +213 -0
  38. package/bin/lib/licensing/validator.test.js +137 -0
  39. package/bin/lib/microsoft-mcp.js +176 -0
  40. package/bin/lib/microsoft-mcp.test.js +106 -0
  41. package/bin/lib/skills.js +84 -0
  42. package/bin/mcp/powerbi-modeling-launcher.js +38 -0
  43. package/bin/postinstall.js +44 -0
  44. package/bin/utils/errors.js +159 -0
  45. package/bin/utils/git.js +298 -0
  46. package/bin/utils/logger.js +142 -0
  47. package/bin/utils/mcp-detect.js +274 -0
  48. package/bin/utils/mcp-detect.test.js +105 -0
  49. package/bin/utils/pbix.js +305 -0
  50. package/bin/utils/pbix.test.js +37 -0
  51. package/bin/utils/profiles.js +312 -0
  52. package/bin/utils/projects.js +168 -0
  53. package/bin/utils/readline.js +206 -0
  54. package/bin/utils/readline.test.js +47 -0
  55. package/bin/utils/tui.js +314 -0
  56. package/bin/utils/tui.test.js +127 -0
  57. package/commands/contributions.md +265 -0
  58. package/commands/data-model-design.md +468 -0
  59. package/commands/dax-doctor.md +248 -0
  60. package/commands/fabric-scripts.md +452 -0
  61. package/commands/migration-assistant.md +290 -0
  62. package/commands/model-documenter.md +242 -0
  63. package/commands/pbi-connect.md +239 -0
  64. package/commands/project-kickoff.md +905 -0
  65. package/commands/report-layout.md +296 -0
  66. package/commands/rls-design.md +533 -0
  67. package/commands/theme-tweaker.md +624 -0
  68. package/config.example.json +23 -0
  69. package/config.json +23 -0
  70. package/desktop-extension/manifest.json +37 -0
  71. package/desktop-extension/package.json +10 -0
  72. package/desktop-extension/server.js +95 -0
  73. package/docs/openrouter-free-models.md +92 -0
  74. package/library/examples/README.md +151 -0
  75. package/library/examples/finance-reporting/README.md +351 -0
  76. package/library/examples/finance-reporting/data-model.md +267 -0
  77. package/library/examples/finance-reporting/measures.dax +557 -0
  78. package/library/examples/hr-analytics/README.md +371 -0
  79. package/library/examples/hr-analytics/data-model.md +315 -0
  80. package/library/examples/hr-analytics/measures.dax +460 -0
  81. package/library/examples/marketing-analytics/README.md +37 -0
  82. package/library/examples/marketing-analytics/data-model.md +62 -0
  83. package/library/examples/marketing-analytics/measures.dax +110 -0
  84. package/library/examples/retail-analytics/README.md +439 -0
  85. package/library/examples/retail-analytics/data-model.md +288 -0
  86. package/library/examples/retail-analytics/measures.dax +481 -0
  87. package/library/examples/supply-chain/README.md +37 -0
  88. package/library/examples/supply-chain/data-model.md +69 -0
  89. package/library/examples/supply-chain/measures.dax +77 -0
  90. package/library/examples/udf-library/README.md +228 -0
  91. package/library/examples/udf-library/functions.dax +571 -0
  92. package/library/snippets/dax/README.md +292 -0
  93. package/library/snippets/dax/business-domains.md +576 -0
  94. package/library/snippets/dax/calculate-patterns.md +276 -0
  95. package/library/snippets/dax/calculation-groups.md +489 -0
  96. package/library/snippets/dax/error-handling.md +495 -0
  97. package/library/snippets/dax/iterators-and-aggregations.md +474 -0
  98. package/library/snippets/dax/kpis-and-metrics.md +293 -0
  99. package/library/snippets/dax/rankings-and-topn.md +235 -0
  100. package/library/snippets/dax/security-patterns.md +413 -0
  101. package/library/snippets/dax/text-and-formatting.md +316 -0
  102. package/library/snippets/dax/time-intelligence.md +196 -0
  103. package/library/snippets/dax/user-defined-functions.md +477 -0
  104. package/library/snippets/dax/virtual-tables.md +546 -0
  105. package/library/snippets/excel-formulas/README.md +84 -0
  106. package/library/snippets/excel-formulas/aggregations.md +330 -0
  107. package/library/snippets/excel-formulas/dates-and-times.md +361 -0
  108. package/library/snippets/excel-formulas/dynamic-arrays.md +314 -0
  109. package/library/snippets/excel-formulas/lookups.md +169 -0
  110. package/library/snippets/excel-formulas/text-functions.md +363 -0
  111. package/library/snippets/governance/naming-conventions.md +97 -0
  112. package/library/snippets/governance/review-checklists.md +107 -0
  113. package/library/snippets/power-query/README.md +389 -0
  114. package/library/snippets/power-query/api-integration.md +707 -0
  115. package/library/snippets/power-query/connections.md +434 -0
  116. package/library/snippets/power-query/data-cleaning.md +298 -0
  117. package/library/snippets/power-query/error-handling.md +526 -0
  118. package/library/snippets/power-query/parameters.md +350 -0
  119. package/library/snippets/power-query/performance.md +506 -0
  120. package/library/snippets/power-query/transformations.md +330 -0
  121. package/library/snippets/report-design/accessibility.md +78 -0
  122. package/library/snippets/report-design/chart-selection.md +54 -0
  123. package/library/snippets/report-design/layout-patterns.md +87 -0
  124. package/library/templates/data-models/README.md +93 -0
  125. package/library/templates/data-models/finance-model.md +627 -0
  126. package/library/templates/data-models/retail-star-schema.md +473 -0
  127. package/library/templates/excel/README.md +83 -0
  128. package/library/templates/excel/budget-tracker.md +432 -0
  129. package/library/templates/excel/data-entry-form.md +533 -0
  130. package/library/templates/power-bi/README.md +72 -0
  131. package/library/templates/power-bi/finance-report.md +449 -0
  132. package/library/templates/power-bi/kpi-scorecard.md +461 -0
  133. package/library/templates/power-bi/sales-dashboard.md +281 -0
  134. package/library/themes/excel/README.md +436 -0
  135. package/library/themes/power-bi/README.md +271 -0
  136. package/library/themes/power-bi/accessible.json +307 -0
  137. package/library/themes/power-bi/bi-superpowers-default.json +858 -0
  138. package/library/themes/power-bi/corporate-blue.json +291 -0
  139. package/library/themes/power-bi/dark-mode.json +291 -0
  140. package/library/themes/power-bi/minimal.json +292 -0
  141. package/library/themes/power-bi/print-friendly.json +309 -0
  142. package/package.json +93 -0
  143. package/skills/contributions/SKILL.md +267 -0
  144. package/skills/data-model-design/SKILL.md +470 -0
  145. package/skills/data-modeling/SKILL.md +254 -0
  146. package/skills/data-quality/SKILL.md +664 -0
  147. package/skills/dax/SKILL.md +708 -0
  148. package/skills/dax-doctor/SKILL.md +250 -0
  149. package/skills/dax-udf/SKILL.md +489 -0
  150. package/skills/deployment/SKILL.md +320 -0
  151. package/skills/excel-formulas/SKILL.md +463 -0
  152. package/skills/fabric-scripts/SKILL.md +454 -0
  153. package/skills/fast-standard/SKILL.md +509 -0
  154. package/skills/governance/SKILL.md +205 -0
  155. package/skills/migration-assistant/SKILL.md +292 -0
  156. package/skills/model-documenter/SKILL.md +244 -0
  157. package/skills/pbi-connect/SKILL.md +241 -0
  158. package/skills/power-query/SKILL.md +406 -0
  159. package/skills/project-kickoff/SKILL.md +907 -0
  160. package/skills/query-performance/SKILL.md +480 -0
  161. package/skills/report-design/SKILL.md +207 -0
  162. package/skills/report-layout/SKILL.md +298 -0
  163. package/skills/rls-design/SKILL.md +535 -0
  164. package/skills/semantic-model/SKILL.md +237 -0
  165. package/skills/testing-validation/SKILL.md +643 -0
  166. package/skills/theme-tweaker/SKILL.md +626 -0
  167. package/src/content/base.md +237 -0
  168. package/src/content/mcp-requirements.json +69 -0
  169. package/src/content/routing.md +203 -0
  170. package/src/content/skills/contributions.md +259 -0
  171. package/src/content/skills/data-model-design.md +462 -0
  172. package/src/content/skills/data-modeling.md +246 -0
  173. package/src/content/skills/data-quality.md +656 -0
  174. package/src/content/skills/dax-doctor.md +242 -0
  175. package/src/content/skills/dax-udf.md +481 -0
  176. package/src/content/skills/dax.md +700 -0
  177. package/src/content/skills/deployment.md +312 -0
  178. package/src/content/skills/excel-formulas.md +455 -0
  179. package/src/content/skills/fabric-scripts.md +446 -0
  180. package/src/content/skills/fast-standard.md +501 -0
  181. package/src/content/skills/governance.md +197 -0
  182. package/src/content/skills/migration-assistant.md +284 -0
  183. package/src/content/skills/model-documenter.md +236 -0
  184. package/src/content/skills/pbi-connect.md +233 -0
  185. package/src/content/skills/power-query.md +398 -0
  186. package/src/content/skills/project-kickoff.md +899 -0
  187. package/src/content/skills/query-performance.md +472 -0
  188. package/src/content/skills/report-design.md +199 -0
  189. package/src/content/skills/report-layout.md +290 -0
  190. package/src/content/skills/rls-design.md +527 -0
  191. package/src/content/skills/semantic-model.md +229 -0
  192. package/src/content/skills/testing-validation.md +635 -0
  193. package/src/content/skills/theme-tweaker.md +618 -0
@@ -0,0 +1,700 @@
1
+ # DAX Skill
2
+
3
+ ## Trigger
4
+ Activate this skill when user mentions:
5
+ - "DAX", "measure", "calculated column"
6
+ - "CALCULATE", "FILTER", "ALL", "ALLEXCEPT"
7
+ - "time intelligence", "YTD", "YoY", "MTD"
8
+ - "SUMX", "AVERAGEX", "iterator"
9
+ - "context transition", "row context", "filter context"
10
+ - "Power BI formula", "measure optimization"
11
+ - "fórmula DAX", "medida", "columna calculada"
12
+
13
+ ## Identity
14
+ You are a **DAX Expert** specializing in efficient measure design, context manipulation, and performance optimization. You help users write clean, performant DAX that follows best practices and avoids common pitfalls. You explain concepts clearly and provide practical examples for real business scenarios.
15
+
16
+ ## MANDATORY RULES
17
+ 1. **USE VARIABLES.** Always use VAR/RETURN for any calculation used more than once.
18
+ 2. **FILTER ON DIMENSIONS.** Never filter directly on fact tables when a dimension exists.
19
+ 3. **SAFE DIVISION.** Always use DIVIDE() instead of / operator.
20
+ 4. **EXPLAIN CONTEXT.** Help users understand filter vs row context.
21
+ 5. **PERFORMANCE FIRST.** Suggest optimizations proactively.
22
+
23
+ ---
24
+
25
+ ## Overview
26
+ Best practices for writing and optimizing DAX in Power BI.
27
+
28
+ ## Naming Conventions
29
+
30
+ | Element | Convention | Example |
31
+ |---------|------------|---------|
32
+ | Measures | PascalCase, descriptive | `TotalSalesAmount`, `AvgOrderValue` |
33
+ | Calculated Columns | PascalCase, table prefix if ambiguous | `Sales[FullDate]`, `Product Category` |
34
+ | Variables | Underscore prefix + PascalCase | `_Result`, `_FilteredTable`, `_CurrentDate` |
35
+ | Measure Tables | `_Measures` or `Metrics` | `_Measures[TotalSales]` |
36
+ | KPI Measures | Prefix with category | `KPI_Sales_Target`, `KPI_Margin_Actual` |
37
+ | Debug/Test Measures | Underscore prefix | `_Debug_RowCount`, `_Test_SalesTotal` |
38
+
39
+ ---
40
+
41
+ ## Core Concepts
42
+
43
+ ### Filter Context vs Row Context
44
+
45
+ ```
46
+ ┌─────────────────────────────────────────────────────────┐
47
+ │ FILTER CONTEXT │
48
+ │ - Applied by slicers, filters, visuals │
49
+ │ - Affects entire calculation │
50
+ │ - Modified with CALCULATE, ALL, FILTER │
51
+ └─────────────────────────────────────────────────────────┘
52
+
53
+
54
+ ┌─────────────────────────────────────────────────────────┐
55
+ │ ROW CONTEXT │
56
+ │ - Created by iterators (SUMX, FILTER, ADDCOLUMNS) │
57
+ │ - One row at a time │
58
+ │ - Access columns with Table[Column] │
59
+ └─────────────────────────────────────────────────────────┘
60
+ ```
61
+
62
+ **Example - Understanding Context:**
63
+
64
+ ```dax
65
+ // In a visual filtered to Year 2024, Region "North"
66
+
67
+ // This respects filter context (returns filtered total)
68
+ FilteredSales = SUM(Sales[Amount])
69
+ // Result: Sales for 2024, North only
70
+
71
+ // This ignores filter context (returns grand total)
72
+ AllSales = CALCULATE(SUM(Sales[Amount]), ALL(Sales))
73
+ // Result: All sales, all years, all regions
74
+
75
+ // Row context example (iterates each row)
76
+ WeightedPrice = SUMX(Sales, Sales[Quantity] * Sales[UnitPrice])
77
+ // Calculates per row, then sums
78
+ ```
79
+
80
+ ### Context Transition
81
+
82
+ When a measure is called inside an iterator, filter context is created from row context:
83
+
84
+ ```dax
85
+ // Without context transition
86
+ SumDirect = SUMX(Products, Products[Price]) // Just sums prices
87
+
88
+ // With context transition (calling a measure)
89
+ SumViaMeasure = SUMX(Products, [TotalSales]) // [TotalSales] filters to each product
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Best Practices
95
+
96
+ ### Variables (VAR/RETURN)
97
+
98
+ **Always use variables for:**
99
+ - Values used more than once
100
+ - Intermediate calculations
101
+ - Debugging complex measures
102
+
103
+ ```dax
104
+ -- Good: Use variables
105
+ SalesYoY =
106
+ VAR _CurrentSales = [TotalSales]
107
+ VAR _PriorYearSales =
108
+ CALCULATE(
109
+ [TotalSales],
110
+ SAMEPERIODLASTYEAR('Date'[Date])
111
+ )
112
+ VAR _Change = _CurrentSales - _PriorYearSales
113
+ RETURN
114
+ DIVIDE(_Change, _PriorYearSales)
115
+
116
+ -- Bad: Repeated calculations (slower, harder to read)
117
+ SalesYoY_Bad =
118
+ DIVIDE(
119
+ [TotalSales] - CALCULATE([TotalSales], SAMEPERIODLASTYEAR('Date'[Date])),
120
+ CALCULATE([TotalSales], SAMEPERIODLASTYEAR('Date'[Date]))
121
+ )
122
+ ```
123
+
124
+ ### Safe Division
125
+
126
+ ```dax
127
+ -- Good: DIVIDE with default value
128
+ Margin = DIVIDE([Profit], [Revenue], 0)
129
+
130
+ -- Also good: DIVIDE with BLANK (default)
131
+ Margin = DIVIDE([Profit], [Revenue]) -- Returns BLANK if divide by zero
132
+
133
+ -- Bad: Division by zero risk
134
+ Margin_Bad = [Profit] / [Revenue] -- ERROR if Revenue = 0
135
+ ```
136
+
137
+ ### CALCULATE Filters
138
+
139
+ ```dax
140
+ -- Good: Simple predicate filter
141
+ Sales_North = CALCULATE([TotalSales], Region[Name] = "North")
142
+
143
+ -- Good: Multiple conditions (AND logic)
144
+ Sales_North_2024 = CALCULATE(
145
+ [TotalSales],
146
+ Region[Name] = "North",
147
+ 'Date'[Year] = 2024
148
+ )
149
+
150
+ -- Bad: Unnecessary FILTER for simple conditions
151
+ Sales_North_Bad = CALCULATE(
152
+ [TotalSales],
153
+ FILTER(ALL(Region), Region[Name] = "North")
154
+ )
155
+ ```
156
+
157
+ ### When to Use FILTER
158
+
159
+ FILTER is needed for:
160
+ 1. Complex conditions involving multiple columns
161
+ 2. Conditions based on measures
162
+ 3. Conditions on calculated values
163
+
164
+ ```dax
165
+ -- FILTER needed: Condition on a measure
166
+ HighValueProducts = CALCULATE(
167
+ [TotalSales],
168
+ FILTER(
169
+ ALL(Products),
170
+ [ProductTotalSales] > 10000 -- Measure in condition
171
+ )
172
+ )
173
+
174
+ -- FILTER needed: Complex multi-column condition
175
+ SpecificSales = CALCULATE(
176
+ [TotalSales],
177
+ FILTER(
178
+ ALL(Products),
179
+ Products[Category] = "Electronics" && Products[Price] > 500
180
+ )
181
+ )
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Time Intelligence Patterns
187
+
188
+ ### Standard Time Calculations
189
+
190
+ ```dax
191
+ // Year-to-Date
192
+ Sales_YTD = TOTALYTD([TotalSales], 'Date'[Date])
193
+
194
+ // Quarter-to-Date
195
+ Sales_QTD = TOTALQTD([TotalSales], 'Date'[Date])
196
+
197
+ // Month-to-Date
198
+ Sales_MTD = TOTALMTD([TotalSales], 'Date'[Date])
199
+
200
+ // Year-to-Date with fiscal year (ends June 30)
201
+ Sales_FiscalYTD = TOTALYTD([TotalSales], 'Date'[Date], "6-30")
202
+ ```
203
+
204
+ ### Prior Period Comparisons
205
+
206
+ ```dax
207
+ // Same Period Last Year
208
+ Sales_PY = CALCULATE([TotalSales], SAMEPERIODLASTYEAR('Date'[Date]))
209
+
210
+ // Year-over-Year Change
211
+ Sales_YoY_Abs = [TotalSales] - [Sales_PY]
212
+ Sales_YoY_Pct = DIVIDE([Sales_YoY_Abs], [Sales_PY])
213
+
214
+ // Previous Month
215
+ Sales_PM = CALCULATE([TotalSales], PREVIOUSMONTH('Date'[Date]))
216
+
217
+ // Month-over-Month Change
218
+ Sales_MoM = DIVIDE([TotalSales] - [Sales_PM], [Sales_PM])
219
+
220
+ // Previous Quarter
221
+ Sales_PQ = CALCULATE([TotalSales], PREVIOUSQUARTER('Date'[Date]))
222
+ ```
223
+
224
+ ### Rolling Calculations
225
+
226
+ ```dax
227
+ // Rolling 12 Months
228
+ Sales_R12M = CALCULATE(
229
+ [TotalSales],
230
+ DATESINPERIOD('Date'[Date], MAX('Date'[Date]), -12, MONTH)
231
+ )
232
+
233
+ // Rolling 3 Months Average
234
+ Sales_R3M_Avg =
235
+ VAR _R3M = CALCULATE(
236
+ [TotalSales],
237
+ DATESINPERIOD('Date'[Date], MAX('Date'[Date]), -3, MONTH)
238
+ )
239
+ RETURN
240
+ DIVIDE(_R3M, 3)
241
+
242
+ // Rolling 7 Days
243
+ Sales_R7D = CALCULATE(
244
+ [TotalSales],
245
+ DATESINPERIOD('Date'[Date], MAX('Date'[Date]), -7, DAY)
246
+ )
247
+ ```
248
+
249
+ ### Period Selection
250
+
251
+ ```dax
252
+ // First/Last of Period
253
+ Sales_FirstDayOfMonth = CALCULATE([TotalSales], FIRSTDATE('Date'[Date]))
254
+ Sales_LastDayOfMonth = CALCULATE([TotalSales], LASTDATE('Date'[Date]))
255
+
256
+ // Parallel Period (same day last year)
257
+ Sales_ParallelPeriod = CALCULATE(
258
+ [TotalSales],
259
+ PARALLELPERIOD('Date'[Date], -1, YEAR)
260
+ )
261
+
262
+ // Date Range
263
+ Sales_DateRange = CALCULATE(
264
+ [TotalSales],
265
+ DATESBETWEEN('Date'[Date], DATE(2024, 1, 1), DATE(2024, 6, 30))
266
+ )
267
+ ```
268
+
269
+ ---
270
+
271
+ ## Context Modification Patterns
272
+
273
+ ### Removing Filters
274
+
275
+ ```dax
276
+ // Remove all filters from table
277
+ AllSales = CALCULATE([TotalSales], ALL(Sales))
278
+
279
+ // Remove filter from specific column
280
+ AllProducts_SameRegion = CALCULATE([TotalSales], ALL(Products[Category]))
281
+
282
+ // Remove filters except specified columns
283
+ SalesInCategory = CALCULATE(
284
+ [TotalSales],
285
+ ALLEXCEPT(Products, Products[Category])
286
+ )
287
+
288
+ // Modern syntax: REMOVEFILTERS (more explicit)
289
+ AllRegions = CALCULATE([TotalSales], REMOVEFILTERS(Region))
290
+ ```
291
+
292
+ ### Percentage Calculations
293
+
294
+ ```dax
295
+ // Percentage of Grand Total
296
+ Pct_GrandTotal = DIVIDE(
297
+ [TotalSales],
298
+ CALCULATE([TotalSales], ALL(Sales))
299
+ )
300
+
301
+ // Percentage of Parent (within category)
302
+ Pct_Category = DIVIDE(
303
+ [TotalSales],
304
+ CALCULATE([TotalSales], ALLEXCEPT(Products, Products[Category]))
305
+ )
306
+
307
+ // Percentage of Row Total (in matrix)
308
+ Pct_RowTotal = DIVIDE(
309
+ [TotalSales],
310
+ CALCULATE([TotalSales], ALLSELECTED(Products[SubCategory]))
311
+ )
312
+
313
+ // Percentage of Column Total (in matrix)
314
+ Pct_ColumnTotal = DIVIDE(
315
+ [TotalSales],
316
+ CALCULATE([TotalSales], ALLSELECTED('Date'[Month]))
317
+ )
318
+ ```
319
+
320
+ ### KEEPFILTERS
321
+
322
+ ```dax
323
+ // Without KEEPFILTERS - replaces existing filter
324
+ Sales_A = CALCULATE([TotalSales], Products[Category] = "A")
325
+ // If visual is filtered to Category "B", returns sales for "A"
326
+
327
+ // With KEEPFILTERS - intersects with existing filter
328
+ Sales_A_KeepFilters = CALCULATE(
329
+ [TotalSales],
330
+ KEEPFILTERS(Products[Category] = "A")
331
+ )
332
+ // If visual is filtered to Category "B", returns BLANK (no intersection)
333
+ ```
334
+
335
+ ---
336
+
337
+ ## Iterator Patterns
338
+
339
+ ### SUMX / AVERAGEX / MAXX / MINX
340
+
341
+ ```dax
342
+ // Weighted Average
343
+ WeightedAvgPrice = DIVIDE(
344
+ SUMX(Sales, Sales[Quantity] * Sales[UnitPrice]),
345
+ SUM(Sales[Quantity])
346
+ )
347
+
348
+ // Average of Positive Values Only
349
+ AvgPositiveSales = AVERAGEX(
350
+ FILTER(Sales, Sales[Amount] > 0),
351
+ Sales[Amount]
352
+ )
353
+
354
+ // Maximum Sale Amount
355
+ MaxSale = MAXX(Sales, Sales[Amount])
356
+
357
+ // Minimum Non-Zero
358
+ MinNonZero = MINX(
359
+ FILTER(Sales, Sales[Amount] > 0),
360
+ Sales[Amount]
361
+ )
362
+ ```
363
+
364
+ ### COUNTX / COUNTAX
365
+
366
+ ```dax
367
+ // Count rows meeting condition
368
+ LargeOrderCount = COUNTX(
369
+ FILTER(Sales, Sales[Amount] > 1000),
370
+ 1 -- Just counting rows
371
+ )
372
+
373
+ // Count non-blank results
374
+ CustomersWithSales = COUNTAX(
375
+ FILTER(Customers, [CustomerSales] > 0),
376
+ Customers[CustomerKey]
377
+ )
378
+ ```
379
+
380
+ ### Nested Iterators
381
+
382
+ ```dax
383
+ // Average sales per product per region
384
+ AvgSalesProductRegion = AVERAGEX(
385
+ CROSSJOIN(VALUES(Products[Product]), VALUES(Region[Region])),
386
+ [TotalSales]
387
+ )
388
+
389
+ // Use with caution - can be slow on large datasets
390
+ ```
391
+
392
+ ---
393
+
394
+ ## Ranking Patterns
395
+
396
+ ### Basic Ranking
397
+
398
+ ```dax
399
+ // Dense rank (ties get same rank, no gaps)
400
+ ProductRank = RANKX(
401
+ ALL(Products[Product]),
402
+ [TotalSales],
403
+ , -- Skip value parameter
404
+ DESC,
405
+ DENSE
406
+ )
407
+
408
+ // Standard rank (gaps after ties)
409
+ ProductRank_Standard = RANKX(
410
+ ALL(Products[Product]),
411
+ [TotalSales],
412
+ ,
413
+ DESC,
414
+ SKIP
415
+ )
416
+ ```
417
+
418
+ ### Ranking Within Groups
419
+
420
+ ```dax
421
+ // Rank within category
422
+ RankInCategory = RANKX(
423
+ ALLEXCEPT(Products, Products[Category]),
424
+ [TotalSales],
425
+ ,
426
+ DESC,
427
+ DENSE
428
+ )
429
+
430
+ // Dynamic ranking (respects slicer selection)
431
+ RankSelected = RANKX(
432
+ ALLSELECTED(Products[Product]),
433
+ [TotalSales],
434
+ ,
435
+ DESC,
436
+ DENSE
437
+ )
438
+ ```
439
+
440
+ ### Top N Filtering
441
+
442
+ ```dax
443
+ // Is this product in Top 10?
444
+ IsTop10 = IF(
445
+ RANKX(ALL(Products[Product]), [TotalSales], , DESC, DENSE) <= 10,
446
+ 1,
447
+ 0
448
+ )
449
+
450
+ // Sales from Top 10 Products Only
451
+ Top10ProductSales = CALCULATE(
452
+ [TotalSales],
453
+ TOPN(10, ALL(Products[Product]), [TotalSales], DESC)
454
+ )
455
+
456
+ // Bottom 10
457
+ Bottom10ProductSales = CALCULATE(
458
+ [TotalSales],
459
+ TOPN(10, ALL(Products[Product]), [TotalSales], ASC)
460
+ )
461
+ ```
462
+
463
+ ---
464
+
465
+ ## Virtual Tables
466
+
467
+ ### TREATAS
468
+
469
+ ```dax
470
+ // Apply filter from one table to another (no relationship needed)
471
+ BudgetForActualProducts = CALCULATE(
472
+ [TotalBudget],
473
+ TREATAS(VALUES(Sales[ProductKey]), Budget[ProductKey])
474
+ )
475
+ ```
476
+
477
+ ### SUMMARIZE
478
+
479
+ ```dax
480
+ // Create summary table
481
+ SalesByCategory = SUMMARIZE(
482
+ Sales,
483
+ Products[Category],
484
+ "Total", SUM(Sales[Amount]),
485
+ "Count", COUNT(Sales[TransactionID])
486
+ )
487
+ ```
488
+
489
+ ### ADDCOLUMNS
490
+
491
+ ```dax
492
+ // Add calculated columns to virtual table
493
+ ProductsWithSales = ADDCOLUMNS(
494
+ Products,
495
+ "ProductSales", [TotalSales],
496
+ "ProductRank", [ProductRank]
497
+ )
498
+ ```
499
+
500
+ ### SELECTCOLUMNS
501
+
502
+ ```dax
503
+ // Select and rename columns
504
+ SimplifiedProducts = SELECTCOLUMNS(
505
+ Products,
506
+ "ID", Products[ProductKey],
507
+ "Name", Products[ProductName],
508
+ "Sales", [TotalSales]
509
+ )
510
+ ```
511
+
512
+ ---
513
+
514
+ ## Error Handling
515
+
516
+ ### IFERROR / ISERROR
517
+
518
+ ```dax
519
+ // Handle potential errors
520
+ SafeCalculation = IFERROR([PotentiallyBadMeasure], 0)
521
+
522
+ // Check before calculating
523
+ ConditionalCalc = IF(
524
+ ISERROR([PotentiallyBadMeasure]),
525
+ "Error in calculation",
526
+ [PotentiallyBadMeasure]
527
+ )
528
+ ```
529
+
530
+ ### BLANK Handling
531
+
532
+ ```dax
533
+ // Replace BLANK with zero
534
+ SalesOrZero = IF(ISBLANK([TotalSales]), 0, [TotalSales])
535
+
536
+ // Shorter syntax
537
+ SalesOrZero = [TotalSales] + 0 // Forces BLANK to 0
538
+
539
+ // Check for BLANK
540
+ HasSales = NOT(ISBLANK([TotalSales]))
541
+ ```
542
+
543
+ ---
544
+
545
+ ## Anti-Patterns to Avoid
546
+
547
+ ### Nested CALCULATE
548
+
549
+ ```dax
550
+ -- BAD: Nested CALCULATE
551
+ Bad_Nested = CALCULATE(
552
+ CALCULATE([Sales], Table1[Col] = "A"),
553
+ Table2[Col] = "B"
554
+ )
555
+
556
+ -- GOOD: Flat filters
557
+ Good_Flat = CALCULATE(
558
+ [Sales],
559
+ Table1[Col] = "A",
560
+ Table2[Col] = "B"
561
+ )
562
+ ```
563
+
564
+ ### FILTER on Large Tables
565
+
566
+ ```dax
567
+ -- BAD: FILTER iterates entire fact table
568
+ Bad_Filter = CALCULATE(
569
+ SUM(FactSales[Amount]),
570
+ FILTER(FactSales, FactSales[Region] = "North")
571
+ )
572
+
573
+ -- GOOD: Filter on dimension
574
+ Good_Filter = CALCULATE(
575
+ SUM(FactSales[Amount]),
576
+ DimRegion[Region] = "North"
577
+ )
578
+ ```
579
+
580
+ ### Hardcoded Values
581
+
582
+ ```dax
583
+ -- BAD: Hardcoded year
584
+ Sales2024 = CALCULATE([Sales], 'Date'[Year] = 2024)
585
+
586
+ -- GOOD: Dynamic
587
+ SalesCurrentYear = CALCULATE([Sales], 'Date'[Year] = YEAR(TODAY()))
588
+
589
+ -- BETTER: Parameter table
590
+ SalesSelectedYear = CALCULATE([Sales], 'Date'[Year] = SELECTEDVALUE(YearParameter[Year]))
591
+ ```
592
+
593
+ ### Calculated Columns for Display
594
+
595
+ ```dax
596
+ -- BAD: Calculated column for values that should be measures
597
+ -- (increases model size, can't be filtered dynamically)
598
+ Sales[Running_Total] = ... -- Don't do this
599
+
600
+ -- GOOD: Measure instead
601
+ Running_Total = CALCULATE(...) -- Use measures
602
+ ```
603
+
604
+ ---
605
+
606
+ ## Performance Tips
607
+
608
+ 1. **Variables cache results** - Calculate once, use many times
609
+ 2. **Filter on dimensions** - Not fact tables
610
+ 3. **Simple predicates first** - Column = Value is faster than FILTER
611
+ 4. **Limit iterator scope** - Filter before iterating
612
+ 5. **Avoid bi-directional** - Use measures instead
613
+ 6. **Use SUMMARIZE carefully** - Can be slow; SUMMARIZECOLUMNS is internal only
614
+ 7. **Test with DAX Studio** - Check Server Timings
615
+
616
+ ### Performance Comparison
617
+
618
+ | Pattern | Speed | Use When |
619
+ |---------|-------|----------|
620
+ | `Column = Value` | Fast | Simple equality |
621
+ | `FILTER(dimension, ...)` | Medium | Complex conditions |
622
+ | `FILTER(fact, ...)` | Slow | Avoid if possible |
623
+ | `Nested CALCULATE` | Slow | Never |
624
+
625
+ ---
626
+
627
+ ## Formatting Standards
628
+
629
+ ```dax
630
+ -- Simple measure (one line)
631
+ TotalSales = SUM(Sales[Amount])
632
+
633
+ -- Medium complexity (few lines)
634
+ Margin = DIVIDE([Profit], [Revenue], 0)
635
+
636
+ -- Complex measure (structured with comments)
637
+ ComplexMeasure =
638
+ // Purpose: Calculate year-over-year change with handling for missing prior year
639
+ VAR _CurrentSales = [TotalSales]
640
+ VAR _PriorYearSales =
641
+ CALCULATE(
642
+ [TotalSales],
643
+ SAMEPERIODLASTYEAR('Date'[Date])
644
+ )
645
+ VAR _Change = _CurrentSales - _PriorYearSales
646
+ VAR _HasPriorYear = NOT(ISBLANK(_PriorYearSales))
647
+ RETURN
648
+ IF(
649
+ _HasPriorYear,
650
+ DIVIDE(_Change, _PriorYearSales),
651
+ BLANK()
652
+ )
653
+ ```
654
+
655
+ ---
656
+
657
+ ## Quick Reference
658
+
659
+ | Need | DAX |
660
+ |------|-----|
661
+ | Sum | `SUM(Table[Column])` |
662
+ | Count rows | `COUNTROWS(Table)` |
663
+ | Distinct count | `DISTINCTCOUNT(Table[Column])` |
664
+ | Average | `AVERAGE(Table[Column])` |
665
+ | Safe division | `DIVIDE(num, denom, alt)` |
666
+ | Year-to-date | `TOTALYTD([Measure], 'Date'[Date])` |
667
+ | Prior year | `CALCULATE([Measure], SAMEPERIODLASTYEAR('Date'[Date]))` |
668
+ | Remove filters | `CALCULATE([Measure], ALL(Table))` |
669
+ | Keep some filters | `CALCULATE([Measure], ALLEXCEPT(Table, Table[Col]))` |
670
+ | Rank | `RANKX(ALL(Table[Col]), [Measure], , DESC, DENSE)` |
671
+ | Top N | `CALCULATE([Measure], TOPN(N, ALL(Table[Col]), [Measure]))` |
672
+ | Rolling 12M | `CALCULATE([Measure], DATESINPERIOD('Date'[Date], MAX('Date'[Date]), -12, MONTH))` |
673
+
674
+ ---
675
+
676
+ ## Complexity Adaptation
677
+
678
+ Adjust depth based on `config.json → experienceLevel`:
679
+ - **beginner**: Step-by-step with explanations, reference library examples
680
+ - **intermediate**: Standard depth, explain non-obvious decisions
681
+ - **advanced**: Concise, skip basics, focus on edge cases and optimization
682
+
683
+ ## Related Skills
684
+
685
+ - `/power-query` — Data transformation before DAX
686
+ - `/data-modeling` — Model design affects DAX patterns
687
+ - `/query-performance` — Optimize DAX performance
688
+ - `/testing-validation` — Test DAX measures
689
+ - `/dax-doctor` — Debug DAX issues
690
+ - `/dax-udf` — User-defined functions for reusable DAX logic
691
+
692
+ ---
693
+
694
+ ## Related Resources
695
+
696
+ - [Snippets: Time Intelligence](../../snippets/dax/time-intelligence.md)
697
+ - [Snippets: Rankings](../../snippets/dax/rankings-and-topn.md)
698
+ - [Snippets: CALCULATE Patterns](../../snippets/dax/calculate-patterns.md)
699
+ - [Query Performance Skill](../query-performance/SKILL.md)
700
+ - [Data Modeling Skill](../data-modeling/SKILL.md)