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