PowerQuery/M-Language Cheatsheet

Cheatsheet for PowerQuery with PowerBI or Excel

Updated: 03 September 2023

Power Query is query language which makes use of the M langauge to transform, manipulate, and query data and is used in different MS data applications such as PowerBI and Excel

Primitives and Operators

Power Query provides some basic literals such as numbers, text, booleans, and lists and they can be defined like so:

TypeExample
Number0, 10, 9999
Text"Hello world"
Logicaltrue, false
list{"hello", 1}, {{"hello", 1}, { "bye", 2 }}

Additionally, there are the usual operators as well as some kind of special ones below:

OperatorExampleResult
Plus +1 + 23
#time(12,23,0) + #duration(0,0,2,0)#time(12,25,0)
Combination &"Hello " & "world""Hello world"
{1} & {2,3}{1,2,3}
[a = 1] & [b = 2][a = 1, b = 2]
Not notLogical NOT
Or orLogical OR
And andLogical AND

Expressions

An expression is a part of a query that can be evaluated, such as "Hello" or Table.FromRows({{"Jeff"}, {"Smith"}}, {"Name"})

Using variables in PowerQuery is done using using the let ... in expression where let defines a block in which variables can be assigned, each assignment separated by a , and in defines the block with the return expression

1
let
2
data = {{"Jeff"}, {"Smith"}},
3
cols = {"Name"}
4
in
5
Table.FromRows(data, cols)

Functions

Thera are also the function expression which can be defined using the following type of syntax for a single line function:

1
MyFunction = (param1, param2, paramN) => param1 + param2 + paramN

Or a more complex multi-line function making use of a let ... in expression and other function calls

1
CreateTable = (colName) =>
2
let
3
data = {{"Jeff"}, {"Smith"}},
4
cols = {colName}
5
in
6
Table.FromRows(data, cols)

And integrating that with the above let ... in expression will look something more like this in a query

1
let
2
CreateTable = (colName) =>
3
let
4
data = {{"Jeff"}, {"Smith"}},
5
cols = {colName}
6
in
7
Table.FromRows(data, cols)
8
in CreateTable("Col Name")

Misc

Pivot Multi-Hot-Encoded Entries as Many Separate Ones

data

IdStartedIn ProgressCompleted
1truefalsefalse
2truetruetrue
3truetruefalse

We can use the following query to pivot our table out like so:

1
= let
2
Filter = (cond, stat) =>
3
Table.AddColumn(
4
Table.SelectColumns(
5
Table.SelectRows(data, cond), {"Id"}
6
), "Stage", each stat
7
),
8
9
initRows = Filter(each true, "Exists"),
10
startedRows = Filter(each [Started], "Started"),
11
progressRows = Filter(each [In Progress], "In Progress"),
12
completedRows = Filter(each [Completed], "Completed")
13
in
14
Table.Combine({initRows, startedRows, progressRows, completedRows})

Which will result in an output data table with:

result

IdStage
1Exists
2Exists
3Exists
1Started
2Started
3Started
2In Progress
3In Progress
2Completed

A Time-Period Based Target Table

Targets are often measured using metrics like YTD or MTD in PowerBI, however this may not be the optimal method as it may alternatively be useful to get the target as a running total for the time period

There’s probably a better way to do this but the method I’ve worked it to create a running target table that only has columns for each target in it’s own row which can then be linked to a Date/calendar table for making targets time-calculable:

1
= let
2
dates = Table.FromColumns(
3
{List.Dates(#date(2016, 1, 1), 2000, #duration(1, 0, 0, 0))}, {"Date"}
4
),
5
6
AddTargetCol = (t, name, target) => Table.AddColumn(t, name, each (target/365)),
7
8
withT1 = AddTargetCol(dates, "Target 1", 5000),
9
withT2 = AddTargetCol(withT1, "Target 2", 10000),
10
withT3 = AddTargetCol(withT2, "Target 3", 100)
11
in
12
withT3

Now, when measuring targets by time you can simply filter the appropriate time period and use a sum of time to display the time-appropriate target