mcpField
P
power-query-m

power-query-m

github.com/josiahsiegelData & databases59106 installsUpdated 19w ago
Repository

About power-query-m

A reference skill for Power Query data transformations in Power BI, covering the M language, query folding, and performance tuning. It also outlines patterns for parameters, error handling, and custom connectors.

Key features

  1. 01M language syntax and table functions
  2. 02Query folding checks and diagnostics
  3. 03Step-by-step transformation optimization
  4. 04Parameterized dynamic data sources
  5. 05try/otherwise error handling
  6. 06Custom connector structure

Use cases

  1. 01Improve Power BI data refresh performance
  2. 02Check whether transformation steps fold
  3. 03Switch environment connections with parameters
  4. 04Build a custom connector for a Web API

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill power-query-m

After installing, type/power-query-min Claude Code to confirm it loaded.

Bundled filesreferences/m-patterns-cookbook.md

Details

From the project README

Power Query (M Language)

Overview

Power Query is the data transformation engine in Power BI, using the M functional language. It handles ETL (Extract, Transform, Load) from sources to the data model. Understanding query folding, step optimization, and M syntax is critical for performant data refresh.

Query Folding

Query folding translates M steps into native source queries (SQL, OData, etc.), pushing computation to the source instead of the mashup engine.

How to check folding:

  1. Right-click a step in Applied Steps > "View Native Query" -- if grayed out, folding broke
  2. Use Query Diagnostics (Tools > Start Diagnostics) to see what queries are sent

Steps that fold (common):

OperationSQL Translation
Remove columnsSELECT (column list)
Filter rowsWHERE clause
Sort rowsORDER BY
Group byGROUP BY
Rename columnsColumn aliases
Change type (basic)CAST
Merge queries (database)JOIN
Top N rowsTOP / LIMIT
Remove duplicatesDISTINCT

Steps that break folding:

OperationWhy
Add custom column (complex)M expression cannot translate to SQL
Pivot/Unpivot (sometimes)Depends on source capability
Merge with non-foldable sourceCannot push cross-source joins
Table.BufferExplicitly materializes in memory
Reorder after custom stepOnce broken, subsequent steps cannot fold
Date/time transforms (some)Source-specific function differences

Golden rule: Put foldable steps BEFORE non-foldable steps. Once folding breaks, all subsequent steps run in the mashup engine.

M Language Essentials

Let Expression (Query Structure)

Every Power Query query is a let...in expression:

let
    Source = Sql.Database("server", "database"),
    Filtered = Table.SelectRows(Source, each [Status] = "Active"),
    Renamed = Table.RenameColumns(Filtered, {{"OldName", "NewName"}}),
    Typed = Table.TransformColumnTypes(Renamed, {{"Amount", type number}})
in
    Typed
Data Types
M TypeDescription
type textString/text
type numberDecimal number
Int64.TypeWhole number (64-bit integer)
type dateDate only
type datetimeDate and time
type datetimezoneDate, time, and timezone
type durationTime duration
type logicalBoolean (true/false)
type binaryBinary data
type nullNull value
Currency.TypeFixed decimal (4 places)
Percentage.TypePercentage
Common Table Functions
// Filter rows
Table.SelectRows(table, each [Column] > 100)

// Add column
Table.AddColumn(table, "NewCol", each [Col1] * [Col2], type number)

// Remove columns
Table.RemoveColumns(table, {"Col1", "Col2"})

// Select columns (keep only these)
Table.SelectColumns(table, {"Col1", "Col2", "Col3"})

// Rename columns
Table.RenameColumns(table, {{"Old1", "New1"}, {"Old2", "New2"}})

// Change types
Table.TransformColumnTypes(table, {{"Col1", type number}, {"Col2", type text}})

// Replace values
Table.ReplaceValue(table, "old", "new", Replacer.ReplaceText, {"Column"})

// Group by
Table.Group(table, {"GroupCol"}, {
    {"Sum", each List.Sum([Amount]), type number},
    {"Count", each Table.RowCount(_), Int64.Type}
})

// Merge (JOIN)
Table.NestedJoin(left, {"KeyCol"}, right, {"KeyCol"}, "Merged", JoinKind.LeftOuter)

// Expand merged columns
Table.ExpandTableColumn(merged, "Merged", {"Col1", "Col2"})

// Pivot
Table.Pivot(table, List.Distinct(table[PivotCol]), "PivotCol", "ValueCol")

// Unpivot
Table.UnpivotOtherColumns(table, {"KeepCol1", "KeepCol2"}, "Attribute", "Value")

// Sort
Table.Sort(table, {{"Col1", Order.Ascending}, {"Col2", Order.Descending}})

// Remove duplicates
Table.Distinct(table, {"KeyCol1", "KeyCol2"})

// Combine/Append tables
Table.Combine({table1, table2, table3})

// Buffer (force materialization)
Table.Buffer(table)
List Functions
// Generate a sequence
{1..100}
List.Numbers(1, 100)
List.Dates(#date(2024,1,1), 365, #duration(1,0,0,0))

// Transform
List.Transform({1,2,3}, each _ * 2)

// Filter
List.Select({1,2,3,4,5}, each _ > 3)

// Aggregate
List.Sum(list), List.Average(list), List.Min(list), List.Max(list)

// Generate with custom logic (pagination pattern)
List.Generate(
    () => [Page = 0, Data = GetPage(0)],
    each [Data] <> null,
    each [Page = [Page] + 1, Data = GetPage([Page] + 1)],
    each [Data]
)

Parameters and Dynamic Sources

Create parameters for environment-specific connections:

// Define parameter in Power Query UI or M:
// Name: ServerName, Type: Text, Current Value: "prod-server.database.windows.net"

// Use in query:
let
    Source = Sql.Database(ServerName, DatabaseName),
    ...

Dynamic source pattern:

let
    BaseUrl = "https://api.example.com/v2/",
    Endpoint = BaseUrl & "data?page=",
    GetPage = (pageNum as number) =>
        let
            url = Endpoint & Number.ToText(pageNum),
            response = Json.Document(Web.Contents(url))
        in
            response[results],
    AllPages = List.Generate(
        () => [i = 1, res = GetPage(1)],
        each List.Count([res]) > 0,
        each [i = [i] + 1, res = GetPage([i] + 1)],
        each [res]
    ),
    Combined = List.Combine(AllPages),
    AsTable = Table.FromList(Combined, Record.FieldValues,
        type table [id = Int64.Type, name = text, value = number])
in
    AsTable

Error Handling

// Try/otherwise pattern
let
    result = try SomeRiskyOperation() otherwise "default"
in
    result

// Try with error record inspection
let
    attempt = try Number.FromText("abc"),
    output = if attempt[HasError]
        then "Error: " & attempt[Error][Message]
        else attempt[Value]
in
    output

// Replace errors in a column
Table.ReplaceErrorValues(table, {{"Column1", null}, {"Column2", 0}})

// Remove error rows
Table.RemoveRowsWithErrors(table, {"Column1", "Column2"})

Custom Connectors

Build custom Power Query connectors using the Power Query SDK:

  1. Install Power Query SDK (VS Code extension)
  2. Create a .mproj project with DataConnector.pq file
  3. Implement the data source function with authentication
  4. Package as .mez file
  5. Deploy to Documents\Power BI Desktop\Custom Connectors or gateway

Basic connector structure:

section MyConnector;

[DataSource.Kind="MyConnector", Publish="MyConnector.Publish"]
shared MyConnector.Contents = (url as text) =>
    let
        source = Web.Contents(url),
        json = Json.Document(source)
    in
        json;

MyConnector = [
    Authentication = [
        Key = [],
        OAuth = [...]
    ],
    Label = "My Custom Connector"
];

MyConnector.Publish = [
    Beta = true,
    Category = "Other",
    ButtonText = {"My Connector", "Connect to My Service"}
];

Performance Optimization

TechniqueImpact
Put foldable steps firstHigh -- pushes work to source
Remove unused columns earlyHigh -- reduces data volume
Filter early, before joinsHigh -- reduces row count
Avoid Table.Buffer unless neededMedium -- prevents unnecessary materialization
Use native queries when folding failsHigh -- bypass mashup engine
Disable "Include in report refresh" for staging queriesMedium -- skips unnecessary refresh
Use Table.Partition for parallel loadingMedium -- parallelizes large tables
Set Privacy Levels correctlyMedium -- incorrect levels block folding

Additional Resources

Reference Files
  • references/m-patterns-cookbook.md -- Common M patterns: web API pagination, incremental load, JSON flattening, CSV handling, SharePoint folder combine

Comments

Markdown supported