This time we’re going bigger than ever. Fabric, Power BI, SQL, AI and more. We're covering it all. You won't want to miss it.
Learn moreDid you hear? There's a new SQL AI Developer certification (DP-800). Start preparing now and be one of the first to get certified. Register now
Power BI has long supported custom functions in Power Query, but DAX lacked a similar capability—until now.
With DAX UDFs, you can define reusable functions with parameters, just like in traditional programming. Instead of copying and pasting logic across multiple measures, you can now write it once and reuse it throughout your model. This makes your code easier to write, understand, maintain, and debug—whether you're working on complex models or simply aiming for cleaner, more maintainable DAX.
Unlike calculation groups, DAX UDFs support parameterization, unlocking a new level of flexibility and reusability.
Once enabled, you can define UDFs using:
After defining a function, you can use it anywhere DAX is supported—measures, calculated columns, and visual calculations./// [function description]FUNCTION <FunctionName> = ( [parameter name] : [parameter type] ) => <body>
DEFINE
/// Multiply takes two parameters and returns the multiplication
FUNCTION Multiply = (
a,
b
) =>
a * b
EVALUATE {
Multiply ( 6, 7 ) // Returns 42
}
In_DQV_you_can_either_update_the_model_with_changes_or_use_the_code_lens_just_ab
In TMDL view, the same function looks like this:
createOrReplace
/// Multiply takes two parameters and returns the multiplication
FUNCTION Multiply = (a, b) => a * bFunctions_are_shown_in_the_model_explorer_under_Semantic_model
DAX Query View: quick queries make it easy to define and evaluate functions.
TMDL view: drag and drop functions into the canvas or use the right-click menu to generate scripts.
In_Dax_Query_View_you_can_use_quick_queries_on_functions_to_evaluate_define_and
In_TMDL_view_you_can_right-click_to_script_a_function
Functions are also included in the semantic model TMDL script and stored in the functions.tmdl file when using a Power BI Project.
function CustomerLifetimeValue =
(CustomerID) =>
CALCULATE (
[Total Sales],
FILTER ( Customer, Customer[Customer ID] = CustomerID )
)
lineageTag: 056365de-2376-4ca3-974d-68b0acb14e47
function AverageOrderValue = (CustomerID) => DIVIDE ( CustomerLifetimeValue( CustomerID ), CALCULATE ( COUNTROWS( Sales ), FILTER ( Customer, Customer[Customer ID] = CustomerID ) ) ) lineageTag: 7b8c76f7-ecf1-428e-a54e-224ba92c4985
/// AddTax returns the amount including tax function AddTax = (amount: numeric) => amount * 1.1 lineageTag: 8b13a3cb-d23c-4a12-8806-6031be3e50b4
DEFINE
/// AddTax returns the amount including tax
FUNCTION AddTax = (amount: numeric) => amount * 1.1TotalWithTax = AddTax([Total Sales])
[type] [subtype] [parameterMode]
| parameterMode | type | subtype |
|---|---|---|
| val: expects a value | anyval, scalar, table | when type = scalar: variant, int64, decimal, double, string, datetime, boolean, numeric. when type = anyval or table: N/A |
| expr: expects an expression | anyref | N/A |
x: scalar int64 val
x: scalar numeric val
x: numeric
x: scalar variant val
x: scalar
DEFINE
FUNCTION PlusX =
( x:scalar int64 val ) =>
x + 1
EVALUATE {
PlusX(41) //returns 42
}
/// converts a date to a datekey
function convertDateToDateKey =
( p_date: variant ) =>
YEAR ( p_date ) * 10000 + MONTH ( p_date ) * 100 + DAY ( p_date )
/// converts p_amount to p_currency, using the p_date’s average or end of day (default) rate.
function convertToCurrency =
(
p_currency: variant,
p_date: variant,
p_use_average_rate: boolean,
p_amount: decimal
) =>
var currencyKey =
IF (
ISINT64 ( p_currency ),
p_currency,
CALCULATE ( MAX ( 'Currency'[CurrencyKey] ), 'Currency'[Code] == p_currency )
)
var dateKey =
SWITCH (
TRUE,
ISINT64 ( p_date ), p_date,
convertDateToDateKey ( p_date )
)
var exchange_rate =
IF (
p_use_average_rate,
CALCULATE (
MAX ( 'Currency Rate'[Average Rate] ),
'Currency Rate'[DateKey] == dateKey,
'Currency Rate'[CurrencyKey] == currencyKey
),
CALCULATE (
MAX( 'Currency Rate'[End Of Day Rate] ),
'Currency Rate'[DateKey] == dateKey,
'Currency Rate'[CurrencyKey] == currencyKey
)
)
var result =
IF (
ISBLANK ( p_currency ) || ISBLANK ( p_date ) || ISBLANK ( p_amount ),
BLANK (),
IF (
ISBLANK ( exchange_rate ),
"no exchange rate available",
exchange_rate * p_amount
)
)
RETURN result
This logic can then be used to define a measure like Total Sales in Local Currency, and optionally paired with a dynamic format string to display the result in the appropriate currency format:
Total Sales in Local Currency =
convertToCurrency (
SELECTEDVALUE ( 'Currency'[Code] ),
SELECTEDVALUE ( 'Date'[DateKey] ),
TRUE,
[Total Sales]
)
CALCULATE (
MAX ( 'Currency'[Format String] ),
'Currency'[Code] == SELECTEDVALUE ( 'Currency'[Code] )
)The_Total_Sales_in_Local_Currency_measure_returns_the_Total_Sales_value_in_local
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.