Power Query¶
RECOMMENDED DEVELOPMENT WORKFLOW (ALWAYS USE THIS)¶
Test BEFORE persisting - avoid polluting workbooks with broken queries:
Step 1: evaluate → Test M code, verify results (catches syntax errors, missing sources)
Step 2: create/update → Store VALIDATED query in workbook
Step 3: refresh/load-to → Load data to destination (worksheet/data-model)
Why this workflow: - evaluate executes M code WITHOUT creating permanent query (test-then-commit) - Returns actual data preview with columns and rows in JSON - Better error messages than COM exceptions from create/update - Temporary queries, sheets, tables, and mashup connections are deleted by exact Location; cleanup failures return an error instead of success - Skip evaluate only for trivial literal tables (#table with hardcoded values)
IF CREATE/UPDATE FAILS: Use evaluate to get detailed Power Query error message, fix code, retry.
Additional evaluate use cases: - Execute one-off queries without creating permanent queries - Ad-hoc data exploration or debugging M code transformations - Quick testing during development (like REPL for M code)
M-Code Formatting and reads:
- Create and Update preserve M code exactly by default and do not call remote services
- Set
format_m_code=trueonly with explicit user consent; it sends M code to powerqueryformatter.com - Remote formatting adds ~100-500ms network latency per call
- Graceful fallback: saves original M code if the formatting service is unavailable
listreturns compact metadata, exact load mode, character count, and at most 80 characters offormulaPreview; it never returns full M code- Use
viewto retrieve one query's complete M code and exact load mode - Read operations return stored text without formatting
Data Model workflow:
Power Query can load data to different destinations: - worksheet / load-to-table (default): Creates an Excel Table on a worksheet - data-model / load-to-data-model: Loads directly to Power Pivot for DAX analysis - both / load-to-both: Loads to worksheet AND Power Pivot - connection-only: Imports query definition without loading data
Destination values are case-insensitive. Unknown values fail before the query is changed; they never fall back to connection-only or another enum default.
To create DAX measures on Power Query data: 1. Use powerquery create/load-to with load_destination='data-model' 2. Then use datamodel to create DAX measures
Alternative path (for existing worksheet tables): 1. Use table with add-to-data-model action 2. Then use datamodel to create DAX measures
Action disambiguation:
- evaluate: CRITICAL - USE THIS FIRST - Execute M code directly, return results WITHOUT creating a permanent query (test before create/update!)
- create: Import NEW query using inline
m_code(FAILS if query already exists - use update instead) - update: Update EXISTING query M code + refresh data (use this if query exists)
- rename: Change query name (requires both
old_nameandnew_name) - load-to: Loads to worksheet or data model or both (not just config change) - CHECKS for sheet conflicts
- unload: Removes data from ALL destinations (worksheet AND Data Model) - keeps query definition
- delete: Completely removes query AND all associated data (worksheet, Data Model connections)
Rename behavior:
- Names are trimmed and compared case-insensitively for uniqueness
- Renaming "Query1" to "query1" is allowed (case-only change, no conflict)
- Renaming "Query1" to " Query1 " is a no-op (trimmed names match)
- No-op (same normalized name) → success with
oldName=newName - Conflict with existing query → error with
errorMessage - M code content is unchanged - only the name changes
- No auto-save: workbook must be saved separately to persist the rename
When to use create vs update:
- Query doesn't exist? → Use create
- Query already exists? → Use update (create will error "already exists")
- Not sure? → Check with list action first, then use update if exists or create if new
- ALWAYS evaluate M code FIRST to catch errors before persisting
List/view load state:
list,view, andget-load-configuse the same exact-identity detectorloadModedistinguishesconnection-only,load-to-table,load-to-data-model, andload-to-bothIsConnectionOnly=truemeans query has NO data destination (not in worksheet, not in Data Model)IsConnectionOnly=falsemeans query loads data SOMEWHERE (worksheet OR Data Model OR both)- A query loaded ONLY to Data Model is NOT connection-only
- If Excel cannot inspect a query,
listfails explicitly instead of silently omitting that query
Inline M code:
- Provide raw M code directly via
m_code - Keep
.pqfiles only for GIT workflows
Create/LoadTo with existing sheets:
- Use
target_cell_addressto place the table on an existing worksheet without deleting other content - Applies to BOTH create and load-to
- If the worksheet already has data and you omit
target_cell_address, the tool returns guidance telling you to provide one - Existing tables are refreshed in-place; specifying a different
target_cell_addressrequires unload + reload - Worksheets that exist but are empty behave like new sheets (default destination = A1)
Common mistakes:
- WARNING: Skipping evaluate → Create/update with untested M code (ERROR: pollutes workbook with broken queries)
- Using create on existing query → ERROR "Query 'X' already exists" (should use update)
- Using update on new query → ERROR "Query 'X' not found" (should use create)
- Calling LoadTo without checking if sheet exists (will error if sheet exists)
- Assuming unload only removes worksheet data → Also removes Data Model connections
- Calling rename without trimming
new_name→ Server trims automatically, " Query " becomes "Query" - Renaming to conflicting name → Check list first if unsure about existing names
- Passing an option from another action (for example
m_codeon delete ortimeout_secondson load-to) → ERROR; category-wide schemas expose the union of options, but each action validates its own subset
Server-specific quirks:
- Validation = execution: M code only validated when data loads/refreshes
- connection-only queries: NOT validated until first execution
- load-to with
load_destination: Applies load config + refreshes (2-in-1) - Single cell returns [[value]] not scalar
- Public timeout inputs are integer seconds. Refresh/refresh-all accepts 0-2147483 and defaults to the 30-minute data-operation timeout when
timeout_seconds/--timeoutis 0 or omitted. For quick queries use a smaller value (e.g., 60-120 seconds). - load-to has no caller timeout parameter and uses the fixed 30-minute data-operation timeout; passing
timeoutto load-to is rejected instead of ignored. - Refresh/refresh-all data-operation timeouts replace the session operation wait rather than layering with it. The session timeout controls startup and operations without a dedicated data timeout, including create/update/evaluate. Session open/create accepts 10-3600 seconds and defaults to 120.
Data Model connection cleanup:
- Unload removes BOTH worksheet ListObjects AND Data Model connections
- Delete removes query, worksheet ListObjects, AND Data Model connections
- Ownership uses the exact case-insensitive mashup
Locationvalue, not connection display names; queries such asAandAAremain isolated
M Code - Server-Specific Notes¶
For full M code language syntax, see m-code-syntax reference.
Column/Field Name Quoting (CRITICAL)¶
M code requires special syntax for identifiers containing hyphens, spaces, or special characters:
| Column Name | Syntax | Notes |
|---|---|---|
Amount | [Amount] | Simple names work without quotes |
Non-Recurring | [#"Non-Recurring"] | Hyphen requires #"..." quoting |
List Price (USD) | [#"List Price (USD)"] | Spaces/parens require quoting |
Service Level 1 | [#"Service Level 1"] | Spaces require quoting |
Common mistake: [Non-Recurring] parses as [Non] - [Recurring] (subtraction!) and fails with cryptic "The name 'X' wasn't recognized" errors.
Rule: If a column name contains anything other than letters, numbers, and underscores, use [#"Column Name"] syntax.
Reading Named Ranges (parameters)¶
Query Chaining¶
Reference other queries by name directly: Source = OtherQueryName
Source Control Pattern¶
- Store M code in
.pqfiles powerquery createorupdatewith inlinem_coderefreshto validate- File name MUST match query name
Query naming: File name MUST match Excel query name exactly.