Quick tour
This quick tour applies to creating Power Query M formula language queries in Power BI Desktop, Power Query in Excel, and Get Data in Excel 2016.
Note: M is a case-sensitive language.
Create a query with Query Editor
To create an advanced query, you use the Query Editor. A mashup query is composed of variables, expressions, and values encapsulated by a let expression. A variable can contain spaces by using the # identifier with the name in quotes as in #"Variable name"
.
A let expression follows this structure:
let
Variablename = expression,
#"Variable name" = expression2
in
Variablename
To create an M query in the Query Editor, you follow this basic process:
- Create a series of query formula steps that start with the let statement.
- Each step is defined by a step variable name which can include spaces by using the # character as
#"Step Name"
. - A formula step can be a custom formula. Please note that the Power Query Formula Language is case sensitive.
- Each query formula step builds upon a previous step by referring to a step by its variable name.
- Output a query formula step using the in statement. Generally, the last query step is used as the in final data set output.
To learn more about expressions and values, see Expressions and values.
Simple Power Query M formula example
Let's assume you have a table that looks like this:
OrderID | CustomerID | Item | Price |
---|---|---|---|
1 | 1 | fishing rod | 100 |
2 | 1 | 1 lb. worms | 5 |
3 | 2 | fishing net | 25 |
And, you want to capitalize each word in the Item column to produce the following table:
OrderID | CustomerID | Item | Price |
---|---|---|---|
1 | 1 | Fishing Rod | 100 |
2 | 1 | 1 Lb. Worms | 5 |
3 | 2 | Fishing Net | 25 |
Here's the code you can paste into the Query Editor's Advanced Editor:
let
Orders = Table.FromRecords({
[OrderID = 1, CustomerID = 1, Item = "fishing rod", Price = 100.0],
[OrderID = 2, CustomerID = 1, Item = "1 lb. worms", Price = 5.0],
[OrderID = 3, CustomerID = 2, Item = "fishing net", Price = 25.0]
}),
#"Capitalized Each Word" = Table.TransformColumns(Orders, {"Item", Text.Proper})
in
#"Capitalized Each Word"
Let's review this simple examle and see how it followed the basic process outlined above:
- You started the query using the
let
statement. - You defined 2 steps using the variable names
Orders
and#"Capitalized Each Word"
. - In the first step you used the
Table.FromRecords
function to create a table from a list of supplied records (learn more about these value types in Structured data values). - In the second step you built upon the previous step by passing its variable name as the first parameter to the
Table.TransformColumns
function. - You then output the result of the last step to the final data set by placing its name after the
in
statement.
Expressions and values
A Power Query M formula language query is composed of formula expression steps that create a mashup query. A formula expression can be evaluated (computed), yielding a value.
Let expression
The let expression encapsulates a set of values to be computed, assigned names, and then used in a subsequent expression that follows the in statement. For example, a let expression could contain a Source
variable that equals the value of the Text.Proper()
formula expression and yields a text value in proper case. This value was assigned the name Source
which is then used following the in statement as the final result of the query.
let
Source = Text.Proper("hello world")
in
Source
In the example above, Text.Proper("hello world")
is evaluated to "Hello World".
The next sections describe value types in the language.
Primitive value
A primitive value is single-part value, such as a number, logical, text, or null. A null value can be used to indicate the absence of any data.
Type | Example value |
---|---|
Binary | 00 00 00 02 // number of points (2) |
Date | 5/23/2015 |
DateTime | 5/23/2015 12:00:00 AM |
DateTimeZone | 5/23/2015 12:00:00 AM -08:00 |
Duration | 15:35:00 |
Logical | true and false |
Null | null |
Number | 0, 1, -1, 1.5, and 2.3e-5 |
Text | "abc" |
Time | 12:34:12 PM |
Function value
A Function is a value which, when invoked with arguments, produces a new value. Functions are written by listing the function’s parameters in parentheses, followed by the goes-to symbol =>, followed by the expression defining the function. For example, to create a function called “MyFunction” that has two parameters and performs a calculation on parameter1 and parameter2:
let
MyFunction = (parameter1, parameter2) => (parameter1 + parameter2) / 2
in
MyFunction
Calling the MyFunction()
returns the result:
let
Source = MyFunction(2, 4)
in
Source
This code produces the value of 3.
Structured data values
The M language supports the following structured data values:
Note: Structured data can contain any M value. To see a couple of examples, see Additional structured data examples.
List
A List is a zero-based ordered sequence of values enclosed in curly brace characters { }. The curly brace characters { } are also used to retrieve an item from a List by index position.
Note: Power Query M supports an infinite list size, but if a list is written as a literal, the list has a fixed length. For example, {1, 2, 3} has a fixed length of 3.
The following are some List examples.
Value | Type |
---|---|
{123, true, "A"} | List containing a number, a logical, and text. |
{1, 2, 3} | List of numbers |
{ {1, 2, 3}, {4, 5, 6} } |
List of List of numbers |
{ [CustomerID = 1, Name = "Bob", Phone = "123-4567"], [CustomerID = 2, Name = "Jim", Phone = "987-6543"] } |
List of Records |
{123, true, "A"}{0} | Get the value of the first item in a List. This expression returns the value 123. |
{ {1, 2, 3}, {4, 5, 6} }{0}{1} |
Get the value of the second item from the first List element. This expression returns the value 2. |
Record
A Record is a set of fields. A field is a name/value pair where the name is a text value that is unique within the field’s record. The syntax for record values allows the names to be written without quotes, a form also referred to as identifiers. An identifier can take the following two forms:
- identifier_name such as OrderID.
- #"identifier name" such as #"Today's data is: ".
Square brace characters [ ] denote the beginning and end of a record expression, and are used to get a field value from a record.
The following example shows a record and how to get the Item field value.
The example record contains fields named "OrderID", "CustomerID", "Item", and "Price" with values 1, 1, "Fishing rod", and 100.00:
let
Source = [
OrderID = 1,
CustomerID = 1,
Item = "Fishing rod",
Price = 100.00
]
in
Source
To get the value of an Item, you use square brackets as Source[Item]:
let
Source = [
OrderID = 1,
CustomerID = 1,
Item = "Fishing rod",
Price = 100.00
]
in
Source[Item] //equals "Fishing rod"
Table
A Table is a set of values organized into named columns and rows. The column type can be implicit or explicit. You can use the #table
function to create a list of column names and a list of rows. A Table of values is a List in a List. The curly brace characters { } are also used to retrieve a row from a Table by index position (see Example 3 – Get a row from a table by index position).
Example 1 - Create a table with implicit column types
let
Source = #table(
{"OrderID", "CustomerID", "Item", "Price"},
{
{1, 1, "Fishing rod", 100.00},
{2, 1, "1 lb. worms", 5.00}
}
)
in
Source
Example 2 – Create a table with explicit column types
let
Source = #table(
type table [OrderID = number, CustomerID = number, Item = text, Price = number],
{
{1, 1, "Fishing rod", 100.00},
{2, 1, "1 lb. worms", 5.00}
}
)
in
Source
Both of the examples above creates a table with the following shape:
OrderID | CustomerID | Item | Price |
---|---|---|---|
1 | 1 | Fishing rod | 100.00 |
2 | 1 | 1 lb. worms | 5.00 |
Example 3 – Get a row from a table by index position
let
Source = #table(
type table [OrderID = number, CustomerID = number, Item = text, Price = number],
{
{1, 1, "Fishing rod", 100.00},
{2, 1, "1 lb. worms", 5.00}
}
)
in
Source{1}
This expression returns the following record:
OrderID | 2 |
CustomerID | 1 |
Item | 1 lb. worms |
Price | 5 |
Additional structured data examples
Structured data can contain any M value. Here are some examples:
Example 1 - List with Primitive values, Function, and Record
let
Source = {
1,
"Bob",
DateTime.ToText(DateTime.LocalNow(), "yyyy-MM-dd"),
[OrderID = 1, CustomerID = 1, Item = "Fishing rod", Price = 100.0]
}
in
Source
Evaluating this expression can be visualized as:
1 | |
"Bob" | |
Today's date in yyyy-MM-dd format | |
OrderID | 2 |
CustomerID | 1 |
Item | 1 lb. worms |
Price | 5 |
Example 2 - Record containing Primitive values and nested Records
let
Source =
[CustomerID = 1, Name = "Bob", Phone = "123-4567", Orders =
{
[OrderID = 1, CustomerID = 1, Item = "Fishing rod", Price = 100.0],
[OrderID = 2, CustomerID = 1, Item = "1 lb. worms", Price = 5.0]
}
]
in
Source
Evaluating this expression can be visualized as:
CustomerID | 1 | |
Name | "Bob" | |
Phone | 123-4567 | |
Orders | OrderID | 1 |
CustomerID | 1 | |
Item | "Fishing rod" | |
Price | 100.0 | |
OrderID | 2 | |
CustomerID | 1 | |
Item | "1 lb. worms" | |
Price | 5.0 |
Note: Although many values can be written literally as an expression, a value is not an expression. For example, the expression 1 evaluates to the value 1; the expression 1+1 evaluates to the value 2. This distinction is subtle, but important. Expressions are recipes for evaluation; values are the results of evaluation.
If expression
The if expression selects between two expressions based on a logical condition. For example:
if 2 > 1 then
2 + 2
else
1 + 1
The first expression (2 + 2) is selected if the logical expression (2 > 1) is true, and the second expression (1 + 1) is selected if it is false. The selected expression (in this case 2 + 2) is evaluated and becomes the result of the if expression (4).
Comments
You can add comments to your code with single-line comments (//) or multi-line comments that begin with /* and end with */.
Example - Single-line comment
let
//Convert to proper case
Source = Text.Proper("hello world")
in
Source
Example - Multi-line comment
/* Capitalize each word in the Item column in the Orders table. Text.Proper
is evaluated for each Item in each table row. */
let
Orders = Table.FromRecords({
[OrderID = 1, CustomerID = 1, Item = "fishing rod", Price = 100.0],
[OrderID = 2, CustomerID = 1, Item = "1 lb. worms", Price = 5.0],
[OrderID = 3, CustomerID = 2, Item = "fishing net", Price = 25.0]
}),
#"Capitalized Each Word" = Table.TransformColumns(Orders, {"Item", Text.Proper})
in
#"Capitalized Each Word"
Evaluation model
The evaluation model of the Power Query M formula language is modeled after the evaluation model commonly found in spreadsheets, where the order of calculations can be determined based on dependencies between the formulas in the cells.
If you have written formulas in a spreadsheet such as Excel, you may recognize the formulas on the left will result in the values on the right when calculated:
A | B | |
---|---|---|
1 | =A2*2 | 4 |
2 | =A3+1 | 2 |
3 | =1 | 1 |
In M, an expression can reference previous expressions by name, and the evaluation process will automatically determine the order in which referenced expressions are calculated.
Let’s use a record to produce an expression which is equivalent to the above spreadsheet example. When initializing the value of a field, you refer to other fields within the record by the name of the field, as follows:
[
A1 = A2 * 2,
A2 = A3 + 1,
A3 = 1
]
The above expression evaluates to the following record:
A1 | 4 |
A2 | 2 |
A3 | 1 |
Records can be contained within, or nested, within other records. You can use the lookup operator ([ ]) to access the fields of a record by name. For example, the following record has a field named Sales containing a record, and a field named Total that accesses the FirstHalf and SecondHalf fields of the Sales record:
[
Sales = [ FirstHalf = 1000, SecondHalf = 1100 ],
Total = Sales[FirstHalf] + Sales[SecondHalf]
]
The above expression evaluates to the following record:
Sales | FirstHalf | 1000 |
SecondHalf | 1100 | |
Total | 2100 |
You use the positional index operator ({ }) to access an item in a list by its numeric index. The values within a list are referred to using a zero-based index from the beginning of the list. For example, the indexes 0 and 1 are used to reference the first and second items in the list below:
[
Sales =
{
[
Year = 2007,
FirstHalf = 1000,
SecondHalf = 1100,
Total = FirstHalf + SecondHalf // equals 2100
],
[
Year = 2008,
FirstHalf = 1200,
SecondHalf = 1300,
Total = FirstHalf + SecondHalf // equals 2500
]
},
#"Total Sales" = Sales{0}[Total] + Sales{1}[Total] // equals 4600
]
Lazy and eager evaluation
List, Record, and Table member expressions, as well as let expressions (See Expressions and values), are evaluated using lazy evaluation: they are evaluated when needed. All other expressions are evaluated using eager evaluation: they are evaluated immediately, when encountered during the evaluation process. A good way to think about this is to remember that evaluating a list or record expression will return a list or record value that knows how its list items or record fields need to computed, when requested (by lookup or index operators).
Operators
The Power Query M formula language includes a set of operators that can be used in an expression. Operators are applied to operands to form symbolic expressions. For example, in the expression 1 + 2 the numbers 1 and 2 are operands and the operator is the addition operator (+).
The meaning of an operator can vary depending on the type of operand values. The language has the following operators:
Plus operator (+)
Expression | Equals |
---|---|
1 + 2 | Numeric addition: 3 |
#time(12,23,0) + #duration(0,0,2,0) | Time arithmetic: #time(12,25,0) |
Combination operator (&)
Function | Equals |
---|---|
"A" & "BC" | Text concatenation: "ABC" |
{1} & {2, 3} | List concatenation: {1, 2, 3} |
[ a = 1 ] & [ b = 2 ] | Record merge: [ a = 1, b = 2 ] |
List of M operators
Common operators which apply to null, logical, number, time, date, datetime, datetimezone, duration, text, binary)
Operator | Description |
---|---|
> | Greater than |
>= | Greater than or equal |
< | Less than |
<= | Less than or equal |
= | Equal |
<> | Not equal |
Logical operators (In addition to Common operators)
Operator | Description |
---|---|
or | Conditional logical OR |
and | Conditional logical AND |
not | Logical NOT |
Number operators (In addition to Common operators)
Operator | Description |
---|---|
+ | Sum |
- | Difference |
* | Product |
/ | Quotient |
+x | Unary plus |
-x | Negation |
Text operators (In addition to Common operators)
Operator | Description |
---|---|
& | Concatenation |
List, record, table operators
Operator | Description |
---|---|
= | Equal |
<> | Not equal |
& | Concatenation |
Record lookup operator
Operator | Description |
---|---|
[] | Access the fields of a record by name. |
List indexer operator
Operator | Description |
---|---|
{} | Access an item in a list by its zero-based numeric index. |
Type compatibility and assertion operators
Operator | Description |
---|---|
is | The expression x is y returns true if the type of x is compatible with y, and returns false if the type of x is not compatible with y. |
as | The expression x as y asserts that the value x is compatible with y as per the is operator. |
Date operators
Operator | Left Operand | Right Operand | Meaning |
---|---|---|---|
x + y | time | duration | Date offset by duration |
x + y | duration | time | Date offset by duration |
x - y | time | duration | Date offset by negated duration |
x - y | time | time | Duration between dates |
x & y | date | time | Merged datetime |
Datetime operators
Operator | Left Operand | Right Operand | Meaning |
---|---|---|---|
x + y | datetime | duration | Datetime offset by duration |
x + y | duration | datetime | Datetime offset by duration |
x - y | datetime | duration | Datetime offset by negated duration |
x - y | datetime | datetime | Duration between datetimes |
Datetimezone operators
Operator | Left Operand | Right Operand | Meaning |
---|---|---|---|
x + y | datetimezone | duration | Datetimezone offset by duration |
x + y | duration | datetimezone | Datetimezone offset by duration |
x - y | datetimezone | duration | Datetimezone offset by negated duration |
x - y | datetimezone | datetimezone | Duration between datetimezones |
Duration operators
Operator | Left Operand | Right Operand | Meaning |
---|---|---|---|
x + y | datetime | duration | Datetime offset by duration |
x + y | duration | datetime | Datetime offset by duration |
x + y | duration | duration | Sum of durations |
x - y | datetime | duration | Datetime offset by negated duration |
x - y | datetime | datetime | Duration between datetimes |
x - y | duration | duration | Difference of durations |
x * y | duration | number | N times a duration |
x * y | number | duration | N times a duration |
x / y | duration | number | Fraction of a duration |
Note: Not all combinations of values may be supported by an operator. Expressions that, when evaluated, encounter undefined operator conditions evaluate to errors. For more information about errors in M, see Errors.
Error example:
Function | Equals |
---|---|
1 + "2" | Error: adding number and text is not supported |
Type conversion
The Power Query M formula language has formulas to convert between types. The following is a summary of conversion formulas in M.
Number
Type conversion | Description |
---|---|
Number.FromText(text as text) as number | Returns a number value from a text value. |
Number.ToText(number as number) as text | Returns a text value from a number value. |
Number.From(value as any) as number | Returns a number value from a value. |
Int32.From(value as any) as number | Returns a 32-bit integer number value from the given value. |
Int64.From(value as any) as number | Returns a 64-bit integer number value from the given value. |
Single.From(value as any) as number | Returns a Single number value from the given value. |
Double.From(value as any) as number | Returns a Double number value from the given value. |
Decimal.From(value as any) as number | Returns a Decimal number value from the given value. |
Currency.From(value as any) as number | Returns a Currency number value from the given value. |
Text
Type conversion | Description |
---|---|
Text.From(value as any) as text | Returns the text representation of a number, date, time, datetime, datetimezone, logical, duration or binary value. |
Logical
Type conversion | Description |
---|---|
Logical.FromText(text as text) as logical | Returns a logical value of true or false from a text value. |
Logical.ToText(logical as logical) as text | Returns a text value from a logical value. |
Logical.From(value as any) as logical | Returns a logical value from a value. |
Date, Time, DateTime, and DateTimeZone
Type conversion | Description |
---|---|
.FromText(text as text) as date, time, datetime, or datetimezone | Returns a date, time, datetime, or datetimezone value from a set of date formats and culture value. |
.ToText(date, time, dateTime, or dateTimeZone as date, time, datetime, or datetimezone) as text |
Returns a text value from a date, time, datetime, or datetimezone value. |
.From(value as any) | Returns a date, time, datetime, or datetimezone value from a value. |
.ToRecord(date, time, dateTime, or dateTimeZone as date, time, datetime, or datetimezone) | Returns a record containing parts of a date, time, datetime, or datetimezone value. |
Metadata
Metadata is information about a value that is associated with a value. Metadata is represented as a record value, called a metadata record. The fields of a metadata record can be used to store the metadata for a value. Every value has a metadata record. If the value of the metadata record has not been specified, then the metadata record is empty (has no fields). Associating a metadata record with a value does not change the value’s behavior in evaluations except for those that explicitly inspect metadata records.
A metadata record value is associated with a value x using the syntax value meta [record]
. For example, the following associates a metadata record with Rating and Tags fields with the text value "Mozart":
"Mozart" meta [
Rating = 5,
Tags = {"Classical"}
]
A metadata record can be accessed for a value using the Value.Metadata
function. In the following example, the expression in the ComposerRating field accesses the metadata record of the value in the Composer field, and then accesses the Rating field of the metadata record.
[
Composer = "Mozart" meta [
Rating = 5,
Tags = {"Classical"}
],
ComposerRating = Value.Metadata(Composer)[Rating] // 5
]
Metadata records are not preserved when a value is used with an operator or function that constructs a new value. For example, if two text values are concatenated using the & operator, the metadata of the resulting text value is an empty record [].
The standard library functions Value.RemoveMetadata
and Value.ReplaceMetadata
can be used to remove all metadata from a value and to replace a value’s metadata.
Errors
An error in Power Query M formula language is an indication that the process of evaluating an expression could not produce a value. Errors are raised by operators and functions encountering error conditions or by using the error expression. Errors are handled using the try expression. When an error is raised, a value is specified that can be used to indicate why the error occurred.
Try expression
A try expression converts values and errors into a record value that indicates whether the try expression handled an error, or not, and either the proper value or the error record it extracted when handling the error. For example, consider the following expression that raises an error and then handles it right away:
try error "negative unit count"
This expression evaluates to the following nested record value, explaining the [HasError]
, [Error]
, and [Message]
field lookups in the unit-price example below.
Error record
[
HasError = true,
Error =
[
Reason = "Expression.Error",
Message = "negative unit count",
Detail = null
]
]
A common case is to replace errors with default values. The try
expression can be used with an optional otherwise
clause to achieve just that in a compact form:
try error "negative unit count" otherwise 42 // equals 42
Error example
let Sales =
[
ProductName = "Fishing rod",
Revenue = 2000,
Units = 1000,
UnitPrice =
if Units = 0 then
error "No Units"
else
Revenue / Units
],
//Get UnitPrice from Sales record
textUnitPrice = try Number.ToText(Sales[UnitPrice]),
Label = "Unit Price: " & (
if textUnitPrice[HasError] then
textUnitPrice[Error][Message]
//Continue expression flow
else
textUnitPrice[Value]
)
in
Label
The above example accesses the Sales[UnitPrice]
field and formats the value producing the result:
"Unit Price: 2"
If the Units field had been zero, then the UnitPrice
field would have raised an error which would have been handled by the try. The resulting value would then have been:
"Unit Price: No Units"