The Analyst's Path

Power Query M language

M is the language Power Query writes behind every step you click. A query is a list of named steps between let and in. Each step is a variable holding a value, and the in line names the step that the query returns. You can open any query you've inherited, read it top to bottom as a numbered recipe, and know which step to click to inspect the table at any point.

3 min readPart of Power Query II: M & PipelinesOpen in course mode

Advertisement

Strip a Power Query query to its skeleton and you'll always find the same three words: let, a comma-separated list of bindings, and in. Here's a complete, minimal query. It reads a worksheet Table called Sales, forces the Revenue column to a number and keeps only the high-value rows:

let
    Source        = Excel.CurrentWorkbook(){[Name="Sales"]}[Content],
    #"Changed Type" = Table.TransformColumnTypes(Source, {{"Revenue", type number}}),
    #"Filtered Rows" = Table.SelectRows(#"Changed Type", each [Revenue] > 100000)
in
    #"Filtered Rows"

Read it out loud, like a paragraph. Let Source be the contents of the Sales Table. Let #"Changed Type" be Source with Revenue retyped. Let #"Filtered Rows" be #"Changed Type" with only the big rows kept. And in the end, hand back #"Filtered Rows".

Every M query you'll ever open has that shape.

Each name to the left of an = is a step, and each step is just a variable holding a value. Here every value happens to be a table. The in clause names the single step whose value the query outputs, and that's almost always the last one.

Advertisement

How do steps and step names work in M?

This is the step-is-a-variable model, and once you've absorbed it, most of the confusion around M goes away. There's no hidden state and no "current selection". The only ordering comes from each step naming the one it builds on. #"Filtered Rows" depends on #"Changed Type" because it mentions it by name. Coming later in the file has nothing to do with it. You could reorder the text of independent steps and nothing would change. Insert a step in the middle and only the steps that reference it are affected.

So where does the odd #"…" come from? A step name with a space or punctuation in it, like the auto-generated Changed Type or Filtered Rows, has to be written as #"Changed Type". The #"…" is just M's way of quoting an identifier that isn't a single bare word. Steps you name yourself without spaces, such as Source, Typed or Result, need no quoting. It's purely cosmetic. It's also the most common reason generated M looks intimidating, and once you know it's only a quoted name, the fog lifts.

Where do you see the M code?

To see the code behind any query, open it in the Power Query Editor and go Home ▸ Advanced Editor. The Advanced Editor shows the entire let … in. The Applied Steps pane on the right is the same code, shown one binding per line. Click a step and the preview shows that step's table. The gear icon re-opens the dialog that generated the step. Renaming a step in Applied Steps (right-click ▸ Rename, or F2) safely rewrites every later reference for you. Editing the name by hand in the Advanced Editor doesn't, and that's a bug we'll come back to.

That already pays off. You can open any query you've inherited, read it top to bottom as a numbered recipe, and know which step to click to inspect the table at any point. Everything from here on is a new kind of step to put in the let.

Advertisement

Part of the course

This page is part of Power Query II: M & Pipelines (EX4.02), in Phase 4: Business models, competitive strategy and moats. The module's flashcards and its quiz are in the app.