@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,389 @@
|
|
|
1
|
+
# Power Query Snippets
|
|
2
|
+
|
|
3
|
+
Production-ready M code patterns for Power BI and Excel data transformation.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Available Snippets
|
|
8
|
+
|
|
9
|
+
| File | Description | Level |
|
|
10
|
+
|------|-------------|-------|
|
|
11
|
+
| [data-cleaning.md](./data-cleaning.md) | Null handling, text cleaning, duplicates, type fixes | Beginner |
|
|
12
|
+
| [transformations.md](./transformations.md) | Unpivot, pivot, split, group, date operations | Intermediate |
|
|
13
|
+
| [connections.md](./connections.md) | SQL, Excel, CSV, API, folder connections | Beginner |
|
|
14
|
+
| [parameters.md](./parameters.md) | Dynamic parameters, environment switching | Intermediate |
|
|
15
|
+
| [performance.md](./performance.md) | Query folding, optimization, memory management | Advanced |
|
|
16
|
+
| [error-handling.md](./error-handling.md) | Try-otherwise, validation, debugging patterns | Intermediate |
|
|
17
|
+
| [api-integration.md](./api-integration.md) | REST APIs, pagination, authentication, error handling | Advanced |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Quick Reference
|
|
22
|
+
|
|
23
|
+
### Filtering
|
|
24
|
+
```m
|
|
25
|
+
// Remove nulls
|
|
26
|
+
Table.SelectRows(Source, each [Column] <> null)
|
|
27
|
+
|
|
28
|
+
// Multiple conditions
|
|
29
|
+
Table.SelectRows(Source, each [Status] = "Active" and [Amount] > 100)
|
|
30
|
+
|
|
31
|
+
// Using list
|
|
32
|
+
Table.SelectRows(Source, each List.Contains({"A", "B", "C"}, [Category]))
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Transformations
|
|
36
|
+
```m
|
|
37
|
+
// Unpivot columns
|
|
38
|
+
Table.UnpivotOtherColumns(Source, {"KeepCol1", "KeepCol2"}, "Attribute", "Value")
|
|
39
|
+
|
|
40
|
+
// Pivot
|
|
41
|
+
Table.Pivot(Source, List.Distinct(Source[Category]), "Category", "Amount", List.Sum)
|
|
42
|
+
|
|
43
|
+
// Group and aggregate
|
|
44
|
+
Table.Group(Source, {"GroupCol"}, {
|
|
45
|
+
{"Sum", each List.Sum([Amount]), type number},
|
|
46
|
+
{"Count", each Table.RowCount(_), Int64.Type}
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Data Types
|
|
51
|
+
```m
|
|
52
|
+
// Set column types
|
|
53
|
+
Table.TransformColumnTypes(Source, {
|
|
54
|
+
{"Amount", type number},
|
|
55
|
+
{"Date", type date},
|
|
56
|
+
{"Name", type text}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// Safe type conversion
|
|
60
|
+
Table.TransformColumns(Source, {{"Column", each try Number.From(_) otherwise null}})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Adding Columns
|
|
64
|
+
```m
|
|
65
|
+
// Conditional column
|
|
66
|
+
Table.AddColumn(Source, "Category", each if [Value] > 100 then "High" else "Low")
|
|
67
|
+
|
|
68
|
+
// Calculated column
|
|
69
|
+
Table.AddColumn(Source, "Total", each [Quantity] * [Price], type number)
|
|
70
|
+
|
|
71
|
+
// From another table (lookup)
|
|
72
|
+
Table.NestedJoin(Source, {"Key"}, LookupTable, {"Key"}, "Lookup", JoinKind.LeftOuter)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Text Operations
|
|
76
|
+
```m
|
|
77
|
+
// Trim and clean
|
|
78
|
+
Table.TransformColumns(Source, {{"Name", each Text.Trim(Text.Clean(_)), type text}})
|
|
79
|
+
|
|
80
|
+
// Split column
|
|
81
|
+
Table.SplitColumn(Source, "FullName", Splitter.SplitTextByDelimiter(" "), {"First", "Last"})
|
|
82
|
+
|
|
83
|
+
// Combine columns
|
|
84
|
+
Table.CombineColumns(Source, {"First", "Last"}, Combiner.CombineTextByDelimiter(" "), "FullName")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Pattern Categories
|
|
90
|
+
|
|
91
|
+
### By Function Area
|
|
92
|
+
|
|
93
|
+
| Category | Key Operations | Use Case |
|
|
94
|
+
|----------|---------------|----------|
|
|
95
|
+
| **Filtering** | SelectRows, RemoveRows | Data subsetting |
|
|
96
|
+
| **Columns** | AddColumn, SelectColumns, RenameColumns | Schema changes |
|
|
97
|
+
| **Reshaping** | Pivot, Unpivot, Transpose | Structure changes |
|
|
98
|
+
| **Aggregation** | Group, Distinct | Summarization |
|
|
99
|
+
| **Joining** | NestedJoin, Merge, Combine | Combining tables |
|
|
100
|
+
| **Types** | TransformColumnTypes, TransformColumns | Data quality |
|
|
101
|
+
|
|
102
|
+
### By Difficulty
|
|
103
|
+
|
|
104
|
+
| Level | Patterns |
|
|
105
|
+
|-------|----------|
|
|
106
|
+
| **Beginner** | Basic filtering, type conversion, column selection |
|
|
107
|
+
| **Intermediate** | Joins, grouping, conditional logic, parameters |
|
|
108
|
+
| **Advanced** | Query folding optimization, custom functions, error handling |
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Query Folding
|
|
113
|
+
|
|
114
|
+
Query folding pushes operations to the data source (SQL) for better performance.
|
|
115
|
+
|
|
116
|
+
### Operations That Fold
|
|
117
|
+
|
|
118
|
+
| Operation | SQL Equivalent |
|
|
119
|
+
|-----------|---------------|
|
|
120
|
+
| Table.SelectRows | WHERE |
|
|
121
|
+
| Table.SelectColumns | SELECT |
|
|
122
|
+
| Table.Sort | ORDER BY |
|
|
123
|
+
| Table.Group | GROUP BY |
|
|
124
|
+
| Table.NestedJoin | JOIN |
|
|
125
|
+
| Table.Distinct | DISTINCT |
|
|
126
|
+
| Table.FirstN | TOP / LIMIT |
|
|
127
|
+
|
|
128
|
+
### Operations That Break Folding
|
|
129
|
+
|
|
130
|
+
| Operation | Why |
|
|
131
|
+
|-----------|-----|
|
|
132
|
+
| Table.AddColumn (custom function) | M-specific logic |
|
|
133
|
+
| Table.Buffer | Forces materialization |
|
|
134
|
+
| List.* in row context | Iterative operations |
|
|
135
|
+
| Table.TransformColumns (complex) | Custom transformations |
|
|
136
|
+
|
|
137
|
+
### Check Folding Status
|
|
138
|
+
|
|
139
|
+
Right-click any step > "View Native Query"
|
|
140
|
+
- If available: Step folds
|
|
141
|
+
- If grayed out: Folding is broken
|
|
142
|
+
|
|
143
|
+
### Optimization Pattern
|
|
144
|
+
|
|
145
|
+
```m
|
|
146
|
+
let
|
|
147
|
+
// 1. Connect
|
|
148
|
+
Source = Sql.Database("server", "database"),
|
|
149
|
+
Table = Source{[Schema="dbo", Item="Sales"]}[Data],
|
|
150
|
+
|
|
151
|
+
// 2. Filter EARLY (folds to WHERE)
|
|
152
|
+
Filtered = Table.SelectRows(Table, each [Year] = 2024),
|
|
153
|
+
|
|
154
|
+
// 3. Select columns EARLY (folds to SELECT)
|
|
155
|
+
Selected = Table.SelectColumns(Filtered, {"Date", "Amount", "CustomerID"}),
|
|
156
|
+
|
|
157
|
+
// 4. Transform LAST (may break folding, but on smaller data)
|
|
158
|
+
Transformed = Table.AddColumn(Selected, "AmountUSD", each [Amount] * 1.1)
|
|
159
|
+
in
|
|
160
|
+
Transformed
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Best Practices
|
|
166
|
+
|
|
167
|
+
### 1. Filter Early, Transform Late
|
|
168
|
+
|
|
169
|
+
```m
|
|
170
|
+
// GOOD: Filter first
|
|
171
|
+
let
|
|
172
|
+
Source = MySource,
|
|
173
|
+
Filtered = Table.SelectRows(Source, each [Status] = "Active"), // Early
|
|
174
|
+
Transformed = Table.AddColumn(Filtered, "NewCol", each [A] + [B]) // Late
|
|
175
|
+
in
|
|
176
|
+
Transformed
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 2. Select Only Needed Columns
|
|
180
|
+
|
|
181
|
+
```m
|
|
182
|
+
// Remove unused columns as soon as possible
|
|
183
|
+
SelectedColumns = Table.SelectColumns(Source, {"ID", "Name", "Amount"})
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 3. Use Descriptive Step Names
|
|
187
|
+
|
|
188
|
+
```m
|
|
189
|
+
// GOOD: Meaningful names
|
|
190
|
+
let
|
|
191
|
+
Source = Excel.Workbook(File.Contents(FilePath)),
|
|
192
|
+
Sales_Sheet = Source{[Item="Sales", Kind="Sheet"]}[Data],
|
|
193
|
+
Promoted_Headers = Table.PromoteHeaders(Sales_Sheet),
|
|
194
|
+
Removed_Null_Rows = Table.SelectRows(Promoted_Headers, each [ID] <> null),
|
|
195
|
+
Set_Column_Types = Table.TransformColumnTypes(Removed_Null_Rows, {
|
|
196
|
+
{"ID", Int64.Type},
|
|
197
|
+
{"Amount", Currency.Type}
|
|
198
|
+
})
|
|
199
|
+
in
|
|
200
|
+
Set_Column_Types
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### 4. Use Parameters for Paths
|
|
204
|
+
|
|
205
|
+
```m
|
|
206
|
+
// Define parameter
|
|
207
|
+
FilePath = "C:\Data\Sales.xlsx" // Easy to change
|
|
208
|
+
|
|
209
|
+
// Use in query
|
|
210
|
+
Source = Excel.Workbook(File.Contents(FilePath))
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 5. Handle Errors Gracefully
|
|
214
|
+
|
|
215
|
+
```m
|
|
216
|
+
// Safe conversion
|
|
217
|
+
Table.TransformColumns(Source, {
|
|
218
|
+
{"Amount", each try Number.From(_) otherwise null, type number}
|
|
219
|
+
})
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### 6. Document Complex Logic
|
|
223
|
+
|
|
224
|
+
```m
|
|
225
|
+
// Add comments for clarity
|
|
226
|
+
let
|
|
227
|
+
Source = MySource,
|
|
228
|
+
|
|
229
|
+
// Remove weekend transactions per business rule BR-123
|
|
230
|
+
FilteredRows = Table.SelectRows(Source, each
|
|
231
|
+
Date.DayOfWeek([Date]) <> Day.Saturday and
|
|
232
|
+
Date.DayOfWeek([Date]) <> Day.Sunday
|
|
233
|
+
)
|
|
234
|
+
in
|
|
235
|
+
FilteredRows
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Performance Tips
|
|
241
|
+
|
|
242
|
+
| Tip | Benefit |
|
|
243
|
+
|-----|---------|
|
|
244
|
+
| Filter early | Less data to process |
|
|
245
|
+
| Select columns early | Less memory |
|
|
246
|
+
| Use Table.Buffer sparingly | Avoid unnecessary materialization |
|
|
247
|
+
| Avoid row-by-row operations | Better engine optimization |
|
|
248
|
+
| Check query folding | Push work to source |
|
|
249
|
+
| Use parameters | Easier maintenance |
|
|
250
|
+
| Disable load for staging queries | Faster refresh |
|
|
251
|
+
|
|
252
|
+
### Memory Management
|
|
253
|
+
|
|
254
|
+
```m
|
|
255
|
+
// DON'T buffer everything
|
|
256
|
+
Bad = Table.Buffer(LargeTable) // Loads all to memory
|
|
257
|
+
|
|
258
|
+
// DO buffer only when needed for multiple references
|
|
259
|
+
let
|
|
260
|
+
BufferedTable = Table.Buffer(SmallTable),
|
|
261
|
+
Max = List.Max(BufferedTable[Amount]),
|
|
262
|
+
Min = List.Min(BufferedTable[Amount])
|
|
263
|
+
in
|
|
264
|
+
// Both use buffered table
|
|
265
|
+
Max - Min
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Common Patterns
|
|
271
|
+
|
|
272
|
+
### COALESCE (First Non-Null)
|
|
273
|
+
|
|
274
|
+
```m
|
|
275
|
+
Table.AddColumn(Source, "Email",
|
|
276
|
+
each if [PrimaryEmail] <> null then [PrimaryEmail]
|
|
277
|
+
else if [SecondaryEmail] <> null then [SecondaryEmail]
|
|
278
|
+
else "unknown@example.com"
|
|
279
|
+
)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Lookup from Another Table
|
|
283
|
+
|
|
284
|
+
```m
|
|
285
|
+
let
|
|
286
|
+
Merged = Table.NestedJoin(
|
|
287
|
+
Source, {"ProductID"},
|
|
288
|
+
ProductTable, {"ProductID"},
|
|
289
|
+
"Product", JoinKind.LeftOuter
|
|
290
|
+
),
|
|
291
|
+
Expanded = Table.ExpandTableColumn(Merged, "Product", {"ProductName", "Category"})
|
|
292
|
+
in
|
|
293
|
+
Expanded
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Running Total
|
|
297
|
+
|
|
298
|
+
```m
|
|
299
|
+
let
|
|
300
|
+
Sorted = Table.Sort(Source, {{"Date", Order.Ascending}}),
|
|
301
|
+
Indexed = Table.AddIndexColumn(Sorted, "Index", 1, 1),
|
|
302
|
+
Running = Table.AddColumn(Indexed, "RunningTotal",
|
|
303
|
+
each List.Sum(List.FirstN(Sorted[Amount], [Index]))
|
|
304
|
+
)
|
|
305
|
+
in
|
|
306
|
+
Running
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Date Table Generation
|
|
310
|
+
|
|
311
|
+
```m
|
|
312
|
+
let
|
|
313
|
+
StartDate = #date(2020, 1, 1),
|
|
314
|
+
EndDate = #date(2025, 12, 31),
|
|
315
|
+
DateList = List.Dates(StartDate, Duration.Days(EndDate - StartDate) + 1, #duration(1, 0, 0, 0)),
|
|
316
|
+
DateTable = Table.FromList(DateList, Splitter.SplitByNothing(), {"Date"}),
|
|
317
|
+
Typed = Table.TransformColumnTypes(DateTable, {{"Date", type date}})
|
|
318
|
+
in
|
|
319
|
+
Typed
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Debugging
|
|
325
|
+
|
|
326
|
+
### Check Row Count at Each Step
|
|
327
|
+
|
|
328
|
+
```m
|
|
329
|
+
// Temporarily add to see counts
|
|
330
|
+
let
|
|
331
|
+
Source = MySource,
|
|
332
|
+
_ = Text.From(Table.RowCount(Source)), // Check in formula bar
|
|
333
|
+
Filtered = Table.SelectRows(Source, each [Status] = "Active"),
|
|
334
|
+
__ = Text.From(Table.RowCount(Filtered)) // Check after filter
|
|
335
|
+
in
|
|
336
|
+
Filtered
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Enable Query Diagnostics
|
|
340
|
+
|
|
341
|
+
1. Tools > Options > Diagnostics
|
|
342
|
+
2. Enable "Query Diagnostics"
|
|
343
|
+
3. Tools > Start Diagnostics
|
|
344
|
+
4. Refresh query
|
|
345
|
+
5. Tools > Stop Diagnostics
|
|
346
|
+
6. Analyze diagnostic tables
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Contributing
|
|
351
|
+
|
|
352
|
+
Add new snippets as `.md` files with:
|
|
353
|
+
|
|
354
|
+
1. **Clear title** - Descriptive name
|
|
355
|
+
2. **Pattern category** - Cleaning, Transform, etc.
|
|
356
|
+
3. **Working M code** - Tested examples
|
|
357
|
+
4. **Parameter explanations** - What to customize
|
|
358
|
+
5. **Usage notes** - When to use
|
|
359
|
+
6. **Performance notes** - Folding impact if relevant
|
|
360
|
+
|
|
361
|
+
### File Template
|
|
362
|
+
|
|
363
|
+
```markdown
|
|
364
|
+
# Pattern Name
|
|
365
|
+
|
|
366
|
+
Description of what this pattern does.
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## Basic Pattern
|
|
371
|
+
|
|
372
|
+
\`\`\`m
|
|
373
|
+
let
|
|
374
|
+
Source = YourSource,
|
|
375
|
+
Result = Table.TransformColumns(Source, ...)
|
|
376
|
+
in
|
|
377
|
+
Result
|
|
378
|
+
\`\`\`
|
|
379
|
+
|
|
380
|
+
## Variations
|
|
381
|
+
|
|
382
|
+
### Variation 1
|
|
383
|
+
...
|
|
384
|
+
|
|
385
|
+
## Usage Notes
|
|
386
|
+
|
|
387
|
+
- Note 1
|
|
388
|
+
- Note 2
|
|
389
|
+
```
|