@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.
- package/.claude-plugin/plugin.json +8 -0
- package/.mcp.json +25 -0
- package/AGENTS.md +244 -0
- package/CHANGELOG.md +265 -0
- package/LICENSE +21 -0
- package/README.md +211 -0
- package/bin/build-plugin.js +30 -0
- package/bin/cli.js +1064 -0
- package/bin/commands/add.js +533 -0
- package/bin/commands/add.test.js +77 -0
- package/bin/commands/build-desktop.js +166 -0
- package/bin/commands/changelog.js +443 -0
- package/bin/commands/diff.js +325 -0
- package/bin/commands/lint.js +419 -0
- package/bin/commands/lint.test.js +103 -0
- package/bin/commands/mcp-setup.js +246 -0
- package/bin/commands/pull.js +287 -0
- package/bin/commands/pull.test.js +36 -0
- package/bin/commands/push.js +231 -0
- package/bin/commands/push.test.js +14 -0
- package/bin/commands/search.js +344 -0
- package/bin/commands/search.test.js +115 -0
- package/bin/commands/setup.js +545 -0
- package/bin/commands/setup.test.js +46 -0
- package/bin/commands/sync-profile.js +405 -0
- package/bin/commands/sync-profile.test.js +14 -0
- package/bin/commands/sync-source.js +418 -0
- package/bin/commands/sync-source.test.js +14 -0
- package/bin/commands/watch.js +206 -0
- package/bin/lib/generators/claude-plugin.js +266 -0
- package/bin/lib/generators/claude-plugin.test.js +110 -0
- package/bin/lib/generators/index.js +116 -0
- package/bin/lib/generators/shared.js +282 -0
- package/bin/lib/licensing/index.js +35 -0
- package/bin/lib/licensing/storage.js +364 -0
- package/bin/lib/licensing/storage.test.js +55 -0
- package/bin/lib/licensing/validator.js +213 -0
- package/bin/lib/licensing/validator.test.js +137 -0
- package/bin/lib/microsoft-mcp.js +176 -0
- package/bin/lib/microsoft-mcp.test.js +106 -0
- package/bin/lib/skills.js +84 -0
- package/bin/mcp/powerbi-modeling-launcher.js +38 -0
- package/bin/postinstall.js +44 -0
- package/bin/utils/errors.js +159 -0
- package/bin/utils/git.js +298 -0
- package/bin/utils/logger.js +142 -0
- package/bin/utils/mcp-detect.js +274 -0
- package/bin/utils/mcp-detect.test.js +105 -0
- package/bin/utils/pbix.js +305 -0
- package/bin/utils/pbix.test.js +37 -0
- package/bin/utils/profiles.js +312 -0
- package/bin/utils/projects.js +168 -0
- package/bin/utils/readline.js +206 -0
- package/bin/utils/readline.test.js +47 -0
- package/bin/utils/tui.js +314 -0
- package/bin/utils/tui.test.js +127 -0
- package/commands/contributions.md +265 -0
- package/commands/data-model-design.md +468 -0
- package/commands/dax-doctor.md +248 -0
- package/commands/fabric-scripts.md +452 -0
- package/commands/migration-assistant.md +290 -0
- package/commands/model-documenter.md +242 -0
- package/commands/pbi-connect.md +239 -0
- package/commands/project-kickoff.md +905 -0
- package/commands/report-layout.md +296 -0
- package/commands/rls-design.md +533 -0
- package/commands/theme-tweaker.md +624 -0
- package/config.example.json +23 -0
- package/config.json +23 -0
- package/desktop-extension/manifest.json +37 -0
- package/desktop-extension/package.json +10 -0
- package/desktop-extension/server.js +95 -0
- package/docs/openrouter-free-models.md +92 -0
- package/library/examples/README.md +151 -0
- package/library/examples/finance-reporting/README.md +351 -0
- package/library/examples/finance-reporting/data-model.md +267 -0
- package/library/examples/finance-reporting/measures.dax +557 -0
- package/library/examples/hr-analytics/README.md +371 -0
- package/library/examples/hr-analytics/data-model.md +315 -0
- package/library/examples/hr-analytics/measures.dax +460 -0
- package/library/examples/marketing-analytics/README.md +37 -0
- package/library/examples/marketing-analytics/data-model.md +62 -0
- package/library/examples/marketing-analytics/measures.dax +110 -0
- package/library/examples/retail-analytics/README.md +439 -0
- package/library/examples/retail-analytics/data-model.md +288 -0
- package/library/examples/retail-analytics/measures.dax +481 -0
- package/library/examples/supply-chain/README.md +37 -0
- package/library/examples/supply-chain/data-model.md +69 -0
- package/library/examples/supply-chain/measures.dax +77 -0
- package/library/examples/udf-library/README.md +228 -0
- package/library/examples/udf-library/functions.dax +571 -0
- package/library/snippets/dax/README.md +292 -0
- package/library/snippets/dax/business-domains.md +576 -0
- package/library/snippets/dax/calculate-patterns.md +276 -0
- package/library/snippets/dax/calculation-groups.md +489 -0
- package/library/snippets/dax/error-handling.md +495 -0
- package/library/snippets/dax/iterators-and-aggregations.md +474 -0
- package/library/snippets/dax/kpis-and-metrics.md +293 -0
- package/library/snippets/dax/rankings-and-topn.md +235 -0
- package/library/snippets/dax/security-patterns.md +413 -0
- package/library/snippets/dax/text-and-formatting.md +316 -0
- package/library/snippets/dax/time-intelligence.md +196 -0
- package/library/snippets/dax/user-defined-functions.md +477 -0
- package/library/snippets/dax/virtual-tables.md +546 -0
- package/library/snippets/excel-formulas/README.md +84 -0
- package/library/snippets/excel-formulas/aggregations.md +330 -0
- package/library/snippets/excel-formulas/dates-and-times.md +361 -0
- package/library/snippets/excel-formulas/dynamic-arrays.md +314 -0
- package/library/snippets/excel-formulas/lookups.md +169 -0
- package/library/snippets/excel-formulas/text-functions.md +363 -0
- package/library/snippets/governance/naming-conventions.md +97 -0
- package/library/snippets/governance/review-checklists.md +107 -0
- package/library/snippets/power-query/README.md +389 -0
- package/library/snippets/power-query/api-integration.md +707 -0
- package/library/snippets/power-query/connections.md +434 -0
- package/library/snippets/power-query/data-cleaning.md +298 -0
- package/library/snippets/power-query/error-handling.md +526 -0
- package/library/snippets/power-query/parameters.md +350 -0
- package/library/snippets/power-query/performance.md +506 -0
- package/library/snippets/power-query/transformations.md +330 -0
- package/library/snippets/report-design/accessibility.md +78 -0
- package/library/snippets/report-design/chart-selection.md +54 -0
- package/library/snippets/report-design/layout-patterns.md +87 -0
- package/library/templates/data-models/README.md +93 -0
- package/library/templates/data-models/finance-model.md +627 -0
- package/library/templates/data-models/retail-star-schema.md +473 -0
- package/library/templates/excel/README.md +83 -0
- package/library/templates/excel/budget-tracker.md +432 -0
- package/library/templates/excel/data-entry-form.md +533 -0
- package/library/templates/power-bi/README.md +72 -0
- package/library/templates/power-bi/finance-report.md +449 -0
- package/library/templates/power-bi/kpi-scorecard.md +461 -0
- package/library/templates/power-bi/sales-dashboard.md +281 -0
- package/library/themes/excel/README.md +436 -0
- package/library/themes/power-bi/README.md +271 -0
- package/library/themes/power-bi/accessible.json +307 -0
- package/library/themes/power-bi/bi-superpowers-default.json +858 -0
- package/library/themes/power-bi/corporate-blue.json +291 -0
- package/library/themes/power-bi/dark-mode.json +291 -0
- package/library/themes/power-bi/minimal.json +292 -0
- package/library/themes/power-bi/print-friendly.json +309 -0
- package/package.json +93 -0
- package/skills/contributions/SKILL.md +267 -0
- package/skills/data-model-design/SKILL.md +470 -0
- package/skills/data-modeling/SKILL.md +254 -0
- package/skills/data-quality/SKILL.md +664 -0
- package/skills/dax/SKILL.md +708 -0
- package/skills/dax-doctor/SKILL.md +250 -0
- package/skills/dax-udf/SKILL.md +489 -0
- package/skills/deployment/SKILL.md +320 -0
- package/skills/excel-formulas/SKILL.md +463 -0
- package/skills/fabric-scripts/SKILL.md +454 -0
- package/skills/fast-standard/SKILL.md +509 -0
- package/skills/governance/SKILL.md +205 -0
- package/skills/migration-assistant/SKILL.md +292 -0
- package/skills/model-documenter/SKILL.md +244 -0
- package/skills/pbi-connect/SKILL.md +241 -0
- package/skills/power-query/SKILL.md +406 -0
- package/skills/project-kickoff/SKILL.md +907 -0
- package/skills/query-performance/SKILL.md +480 -0
- package/skills/report-design/SKILL.md +207 -0
- package/skills/report-layout/SKILL.md +298 -0
- package/skills/rls-design/SKILL.md +535 -0
- package/skills/semantic-model/SKILL.md +237 -0
- package/skills/testing-validation/SKILL.md +643 -0
- package/skills/theme-tweaker/SKILL.md +626 -0
- package/src/content/base.md +237 -0
- package/src/content/mcp-requirements.json +69 -0
- package/src/content/routing.md +203 -0
- package/src/content/skills/contributions.md +259 -0
- package/src/content/skills/data-model-design.md +462 -0
- package/src/content/skills/data-modeling.md +246 -0
- package/src/content/skills/data-quality.md +656 -0
- package/src/content/skills/dax-doctor.md +242 -0
- package/src/content/skills/dax-udf.md +481 -0
- package/src/content/skills/dax.md +700 -0
- package/src/content/skills/deployment.md +312 -0
- package/src/content/skills/excel-formulas.md +455 -0
- package/src/content/skills/fabric-scripts.md +446 -0
- package/src/content/skills/fast-standard.md +501 -0
- package/src/content/skills/governance.md +197 -0
- package/src/content/skills/migration-assistant.md +284 -0
- package/src/content/skills/model-documenter.md +236 -0
- package/src/content/skills/pbi-connect.md +233 -0
- package/src/content/skills/power-query.md +398 -0
- package/src/content/skills/project-kickoff.md +899 -0
- package/src/content/skills/query-performance.md +472 -0
- package/src/content/skills/report-design.md +199 -0
- package/src/content/skills/report-layout.md +290 -0
- package/src/content/skills/rls-design.md +527 -0
- package/src/content/skills/semantic-model.md +229 -0
- package/src/content/skills/testing-validation.md +635 -0
- package/src/content/skills/theme-tweaker.md +618 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
# Iterator Functions and Advanced Aggregations
|
|
2
|
+
|
|
3
|
+
Patterns for SUMX, AVERAGEX, MAXX, MINX, COUNTX, and related iterator functions.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Basic Iterator Patterns
|
|
8
|
+
|
|
9
|
+
### SUMX - Row-by-Row Calculation
|
|
10
|
+
|
|
11
|
+
```dax
|
|
12
|
+
-- Calculate extended price (quantity × unit price)
|
|
13
|
+
Revenue =
|
|
14
|
+
SUMX(
|
|
15
|
+
Sales,
|
|
16
|
+
Sales[Quantity] * Sales[UnitPrice]
|
|
17
|
+
)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```dax
|
|
21
|
+
-- With discount applied
|
|
22
|
+
Revenue_Net =
|
|
23
|
+
SUMX(
|
|
24
|
+
Sales,
|
|
25
|
+
Sales[Quantity] * Sales[UnitPrice] * (1 - Sales[Discount])
|
|
26
|
+
)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### AVERAGEX - Average of Calculated Values
|
|
30
|
+
|
|
31
|
+
```dax
|
|
32
|
+
-- Average order value
|
|
33
|
+
Avg_Order_Value =
|
|
34
|
+
AVERAGEX(
|
|
35
|
+
VALUES(Sales[OrderID]),
|
|
36
|
+
CALCULATE(SUM(Sales[Amount]))
|
|
37
|
+
)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```dax
|
|
41
|
+
-- Average unit price weighted by quantity
|
|
42
|
+
Weighted_Avg_Price =
|
|
43
|
+
DIVIDE(
|
|
44
|
+
SUMX(Sales, Sales[Quantity] * Sales[UnitPrice]),
|
|
45
|
+
SUM(Sales[Quantity])
|
|
46
|
+
)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### MAXX/MINX - Extremes of Calculated Values
|
|
50
|
+
|
|
51
|
+
```dax
|
|
52
|
+
-- Highest single transaction
|
|
53
|
+
Max_Transaction =
|
|
54
|
+
MAXX(
|
|
55
|
+
Sales,
|
|
56
|
+
Sales[Quantity] * Sales[UnitPrice]
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```dax
|
|
61
|
+
-- Lowest performing product's sales
|
|
62
|
+
Min_Product_Sales =
|
|
63
|
+
MINX(
|
|
64
|
+
VALUES(Products[ProductName]),
|
|
65
|
+
CALCULATE(SUM(Sales[Amount]))
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```dax
|
|
70
|
+
-- Best performing month
|
|
71
|
+
Best_Month_Sales =
|
|
72
|
+
MAXX(
|
|
73
|
+
VALUES('Date'[MonthYear]),
|
|
74
|
+
CALCULATE(SUM(Sales[Amount]))
|
|
75
|
+
)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### COUNTX - Conditional Counting
|
|
79
|
+
|
|
80
|
+
```dax
|
|
81
|
+
-- Count high-value transactions
|
|
82
|
+
High_Value_Count =
|
|
83
|
+
COUNTX(
|
|
84
|
+
FILTER(Sales, Sales[Amount] > 1000),
|
|
85
|
+
Sales[TransactionID]
|
|
86
|
+
)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```dax
|
|
90
|
+
-- Count profitable products
|
|
91
|
+
Profitable_Products =
|
|
92
|
+
COUNTX(
|
|
93
|
+
FILTER(
|
|
94
|
+
ALL(Products),
|
|
95
|
+
CALCULATE([ProfitMargin]) > 0.15
|
|
96
|
+
),
|
|
97
|
+
Products[ProductID]
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Advanced Iterator Patterns
|
|
104
|
+
|
|
105
|
+
### Nested Iterators
|
|
106
|
+
|
|
107
|
+
```dax
|
|
108
|
+
-- Total by customer by product (double iteration)
|
|
109
|
+
Customer_Product_Total =
|
|
110
|
+
SUMX(
|
|
111
|
+
VALUES(Customers[CustomerName]),
|
|
112
|
+
SUMX(
|
|
113
|
+
VALUES(Products[ProductName]),
|
|
114
|
+
CALCULATE(SUM(Sales[Amount]))
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```dax
|
|
120
|
+
-- Average of customer totals
|
|
121
|
+
Avg_Customer_Total =
|
|
122
|
+
AVERAGEX(
|
|
123
|
+
VALUES(Customers[CustomerID]),
|
|
124
|
+
CALCULATE(SUM(Sales[Amount]))
|
|
125
|
+
)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### RANKX - Dynamic Rankings
|
|
129
|
+
|
|
130
|
+
```dax
|
|
131
|
+
-- Rank products by sales
|
|
132
|
+
Product_Rank =
|
|
133
|
+
RANKX(
|
|
134
|
+
ALL(Products[ProductName]),
|
|
135
|
+
CALCULATE(SUM(Sales[Amount])),
|
|
136
|
+
,
|
|
137
|
+
DESC,
|
|
138
|
+
DENSE
|
|
139
|
+
)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```dax
|
|
143
|
+
-- Rank within category
|
|
144
|
+
Product_Rank_InCategory =
|
|
145
|
+
RANKX(
|
|
146
|
+
ALLEXCEPT(Products, Products[Category]),
|
|
147
|
+
CALCULATE(SUM(Sales[Amount])),
|
|
148
|
+
,
|
|
149
|
+
DESC,
|
|
150
|
+
DENSE
|
|
151
|
+
)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```dax
|
|
155
|
+
-- Dynamic rank (respects filters)
|
|
156
|
+
Product_Rank_Dynamic =
|
|
157
|
+
IF(
|
|
158
|
+
HASONEVALUE(Products[ProductName]),
|
|
159
|
+
RANKX(
|
|
160
|
+
ALLSELECTED(Products[ProductName]),
|
|
161
|
+
CALCULATE(SUM(Sales[Amount])),
|
|
162
|
+
,
|
|
163
|
+
DESC,
|
|
164
|
+
DENSE
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### CONCATENATEX - String Aggregation
|
|
170
|
+
|
|
171
|
+
```dax
|
|
172
|
+
-- List of products purchased
|
|
173
|
+
Products_Purchased =
|
|
174
|
+
CONCATENATEX(
|
|
175
|
+
VALUES(Products[ProductName]),
|
|
176
|
+
Products[ProductName],
|
|
177
|
+
", ",
|
|
178
|
+
Products[ProductName], ASC
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```dax
|
|
183
|
+
-- Top 3 products by sales
|
|
184
|
+
Top3_Products =
|
|
185
|
+
CONCATENATEX(
|
|
186
|
+
TOPN(
|
|
187
|
+
3,
|
|
188
|
+
VALUES(Products[ProductName]),
|
|
189
|
+
CALCULATE(SUM(Sales[Amount])),
|
|
190
|
+
DESC
|
|
191
|
+
),
|
|
192
|
+
Products[ProductName],
|
|
193
|
+
", ",
|
|
194
|
+
CALCULATE(SUM(Sales[Amount])), DESC
|
|
195
|
+
)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### PRODUCTX - Compound Growth
|
|
199
|
+
|
|
200
|
+
```dax
|
|
201
|
+
-- Compound monthly growth rate
|
|
202
|
+
CAGR =
|
|
203
|
+
VAR _StartValue = CALCULATE(SUM(Sales[Amount]), FIRSTDATE('Date'[Date]))
|
|
204
|
+
VAR _EndValue = CALCULATE(SUM(Sales[Amount]), LASTDATE('Date'[Date]))
|
|
205
|
+
VAR _Periods = DATEDIFF(MIN('Date'[Date]), MAX('Date'[Date]), YEAR)
|
|
206
|
+
RETURN
|
|
207
|
+
IF(
|
|
208
|
+
_Periods > 0 && _StartValue > 0,
|
|
209
|
+
POWER(DIVIDE(_EndValue, _StartValue), DIVIDE(1, _Periods)) - 1
|
|
210
|
+
)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```dax
|
|
214
|
+
-- Geometric mean of growth rates
|
|
215
|
+
Geometric_Avg_Growth =
|
|
216
|
+
VAR _GrowthTable =
|
|
217
|
+
ADDCOLUMNS(
|
|
218
|
+
SUMMARIZE(Sales, 'Date'[Year]),
|
|
219
|
+
"@Growth", 1 + DIVIDE(
|
|
220
|
+
CALCULATE(SUM(Sales[Amount])) - CALCULATE(SUM(Sales[Amount]), PREVIOUSYEAR('Date'[Date])),
|
|
221
|
+
CALCULATE(SUM(Sales[Amount]), PREVIOUSYEAR('Date'[Date]))
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
VAR _Product =
|
|
225
|
+
PRODUCTX(
|
|
226
|
+
FILTER(_GrowthTable, [@Growth] > 0),
|
|
227
|
+
[@Growth]
|
|
228
|
+
)
|
|
229
|
+
VAR _Count =
|
|
230
|
+
COUNTROWS(FILTER(_GrowthTable, [@Growth] > 0))
|
|
231
|
+
RETURN
|
|
232
|
+
IF(_Count > 0, POWER(_Product, 1 / _Count) - 1)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Performance-Optimized Patterns
|
|
238
|
+
|
|
239
|
+
### Using Variables with Iterators
|
|
240
|
+
|
|
241
|
+
```dax
|
|
242
|
+
-- Optimized: Store table reference in variable
|
|
243
|
+
Revenue_Optimized =
|
|
244
|
+
VAR _SalesTable = Sales
|
|
245
|
+
RETURN
|
|
246
|
+
SUMX(
|
|
247
|
+
_SalesTable,
|
|
248
|
+
[Quantity] * [UnitPrice]
|
|
249
|
+
)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
```dax
|
|
253
|
+
-- Avoid recalculating in iterator
|
|
254
|
+
Margin_Optimized =
|
|
255
|
+
VAR _TotalCost = SUM(Sales[Cost])
|
|
256
|
+
VAR _TotalRevenue = SUM(Sales[Revenue])
|
|
257
|
+
RETURN
|
|
258
|
+
DIVIDE(_TotalRevenue - _TotalCost, _TotalRevenue)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### GENERATE vs Nested SUMX
|
|
262
|
+
|
|
263
|
+
```dax
|
|
264
|
+
-- Using GENERATE for better performance
|
|
265
|
+
Sales_Analysis =
|
|
266
|
+
VAR _CustomerSales =
|
|
267
|
+
GENERATE(
|
|
268
|
+
VALUES(Customers[CustomerID]),
|
|
269
|
+
ROW("@Sales", CALCULATE(SUM(Sales[Amount])))
|
|
270
|
+
)
|
|
271
|
+
RETURN
|
|
272
|
+
AVERAGEX(_CustomerSales, [@Sales])
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### ADDCOLUMNS for Pre-Calculation
|
|
276
|
+
|
|
277
|
+
```dax
|
|
278
|
+
-- Pre-calculate values before iteration
|
|
279
|
+
Avg_Profit_Margin =
|
|
280
|
+
VAR _ProductMetrics =
|
|
281
|
+
ADDCOLUMNS(
|
|
282
|
+
ALL(Products[ProductName]),
|
|
283
|
+
"@Revenue", CALCULATE(SUM(Sales[Amount])),
|
|
284
|
+
"@Cost", CALCULATE(SUM(Sales[Cost]))
|
|
285
|
+
)
|
|
286
|
+
RETURN
|
|
287
|
+
AVERAGEX(
|
|
288
|
+
_ProductMetrics,
|
|
289
|
+
DIVIDE([@Revenue] - [@Cost], [@Revenue])
|
|
290
|
+
)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Statistical Functions
|
|
296
|
+
|
|
297
|
+
### Standard Deviation (Sample)
|
|
298
|
+
|
|
299
|
+
```dax
|
|
300
|
+
StdDev_Sales =
|
|
301
|
+
VAR _Avg = AVERAGEX(VALUES('Date'[Month]), CALCULATE(SUM(Sales[Amount])))
|
|
302
|
+
VAR _Variance =
|
|
303
|
+
AVERAGEX(
|
|
304
|
+
VALUES('Date'[Month]),
|
|
305
|
+
POWER(CALCULATE(SUM(Sales[Amount])) - _Avg, 2)
|
|
306
|
+
)
|
|
307
|
+
RETURN
|
|
308
|
+
SQRT(_Variance)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Median Using MEDIANX
|
|
312
|
+
|
|
313
|
+
```dax
|
|
314
|
+
Median_Order_Value =
|
|
315
|
+
MEDIANX(
|
|
316
|
+
VALUES(Sales[OrderID]),
|
|
317
|
+
CALCULATE(SUM(Sales[Amount]))
|
|
318
|
+
)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Percentile Calculation
|
|
322
|
+
|
|
323
|
+
```dax
|
|
324
|
+
Percentile_75_Sales =
|
|
325
|
+
VAR _AllCustomerSales =
|
|
326
|
+
ADDCOLUMNS(
|
|
327
|
+
VALUES(Customers[CustomerID]),
|
|
328
|
+
"@Sales", CALCULATE(SUM(Sales[Amount]))
|
|
329
|
+
)
|
|
330
|
+
VAR _75thPercentile =
|
|
331
|
+
PERCENTILEX.INC(_AllCustomerSales, [@Sales], 0.75)
|
|
332
|
+
RETURN
|
|
333
|
+
_75thPercentile
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Coefficient of Variation
|
|
337
|
+
|
|
338
|
+
```dax
|
|
339
|
+
CV_Sales =
|
|
340
|
+
VAR _Avg = AVERAGEX(VALUES('Date'[Month]), CALCULATE(SUM(Sales[Amount])))
|
|
341
|
+
VAR _StdDev =
|
|
342
|
+
SQRT(
|
|
343
|
+
AVERAGEX(
|
|
344
|
+
VALUES('Date'[Month]),
|
|
345
|
+
POWER(CALCULATE(SUM(Sales[Amount])) - _Avg, 2)
|
|
346
|
+
)
|
|
347
|
+
)
|
|
348
|
+
RETURN
|
|
349
|
+
DIVIDE(_StdDev, _Avg)
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## FILTER vs Iterator Performance
|
|
355
|
+
|
|
356
|
+
### When to Use FILTER
|
|
357
|
+
|
|
358
|
+
```dax
|
|
359
|
+
-- Good: FILTER with simple column condition (foldable)
|
|
360
|
+
Sales_HighValue =
|
|
361
|
+
CALCULATE(
|
|
362
|
+
SUM(Sales[Amount]),
|
|
363
|
+
Sales[Amount] > 1000
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
-- Better than iterator when filtering on columns
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### When to Use Iterator
|
|
370
|
+
|
|
371
|
+
```dax
|
|
372
|
+
-- Good: Complex row-by-row calculation
|
|
373
|
+
Net_Revenue =
|
|
374
|
+
SUMX(
|
|
375
|
+
Sales,
|
|
376
|
+
(Sales[Quantity] * Sales[UnitPrice]) - Sales[Discount] - Sales[Tax]
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
-- Necessary when calculation spans multiple columns per row
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### Hybrid Approach
|
|
383
|
+
|
|
384
|
+
```dax
|
|
385
|
+
-- Combine for best performance
|
|
386
|
+
Profitable_Revenue =
|
|
387
|
+
SUMX(
|
|
388
|
+
FILTER(
|
|
389
|
+
Sales,
|
|
390
|
+
Sales[ProfitFlag] = TRUE() -- Simple filter first
|
|
391
|
+
),
|
|
392
|
+
Sales[Quantity] * Sales[UnitPrice] * (1 - Sales[Discount]) -- Then iterate
|
|
393
|
+
)
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Common Mistakes to Avoid
|
|
399
|
+
|
|
400
|
+
### Mistake 1: Unnecessary Context Transition
|
|
401
|
+
|
|
402
|
+
```dax
|
|
403
|
+
-- Bad: Forces context transition on every row
|
|
404
|
+
Revenue_Bad =
|
|
405
|
+
SUMX(
|
|
406
|
+
Sales,
|
|
407
|
+
CALCULATE(Sales[Quantity] * Sales[UnitPrice])
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
-- Good: No CALCULATE needed
|
|
411
|
+
Revenue_Good =
|
|
412
|
+
SUMX(
|
|
413
|
+
Sales,
|
|
414
|
+
Sales[Quantity] * Sales[UnitPrice]
|
|
415
|
+
)
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Mistake 2: Iterating Over Wrong Table
|
|
419
|
+
|
|
420
|
+
```dax
|
|
421
|
+
-- Bad: Iterates over entire table
|
|
422
|
+
Avg_Product_Sales_Bad =
|
|
423
|
+
AVERAGEX(
|
|
424
|
+
Sales, -- Wrong! Iterates every row
|
|
425
|
+
Sales[Amount]
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
-- Good: Iterate over unique products
|
|
429
|
+
Avg_Product_Sales_Good =
|
|
430
|
+
AVERAGEX(
|
|
431
|
+
VALUES(Products[ProductName]), -- Correct: One iteration per product
|
|
432
|
+
CALCULATE(SUM(Sales[Amount]))
|
|
433
|
+
)
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Mistake 3: Missing ALL in Rankings
|
|
437
|
+
|
|
438
|
+
```dax
|
|
439
|
+
-- Bad: Rank doesn't work correctly with filters
|
|
440
|
+
Rank_Bad =
|
|
441
|
+
RANKX(
|
|
442
|
+
Products, -- Wrong! Affected by filter context
|
|
443
|
+
[Sales]
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
-- Good: Use ALL for consistent ranking
|
|
447
|
+
Rank_Good =
|
|
448
|
+
RANKX(
|
|
449
|
+
ALL(Products[ProductName]), -- Correct: Ranks all products
|
|
450
|
+
CALCULATE(SUM(Sales[Amount]))
|
|
451
|
+
)
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## Usage Notes
|
|
457
|
+
|
|
458
|
+
1. **Iterator functions iterate row by row** - They're powerful but can be slow on large tables
|
|
459
|
+
2. **Use simple aggregations when possible** - SUM, AVERAGE, COUNT are faster than iterators
|
|
460
|
+
3. **Pre-filter tables** - Use FILTER before SUMX to reduce iterations
|
|
461
|
+
4. **Store repeated calculations in variables** - Avoid recalculating inside iterators
|
|
462
|
+
5. **Use ADDCOLUMNS/GENERATE** - Create virtual tables for complex multi-step calculations
|
|
463
|
+
6. **DENSE vs SKIP in RANKX** - DENSE: no gaps; SKIP: gaps for ties
|
|
464
|
+
|
|
465
|
+
## Performance Guidelines
|
|
466
|
+
|
|
467
|
+
| Operation | Rows | Performance |
|
|
468
|
+
|-----------|------|-------------|
|
|
469
|
+
| SUMX/AVERAGEX | < 100K | Fast |
|
|
470
|
+
| SUMX/AVERAGEX | 100K - 1M | Monitor |
|
|
471
|
+
| SUMX/AVERAGEX | > 1M | Optimize |
|
|
472
|
+
| Nested iterators | Any | Expensive |
|
|
473
|
+
| RANKX with ALL | < 10K unique | Fast |
|
|
474
|
+
| RANKX with ALL | > 10K unique | Monitor |
|