Uma UDF empacota uma lógica DAX com nome e parâmetros para reutilizar em medidas, colunas calculadas, cálculos visuais e outras funções. Está disponível para todos (GA) no Desktop e no Service desde junho/2026 e exige nível de compatibilidade do modelo 1702 ou superior.
1. Onde criar
| Onde | Como gravar no modelo |
|---|---|
| DAX Query View | CodeLens Update model: Add new function acima da função, ou Update model with changes para todas |
| TMDL view | Botão Apply. No projeto .pbip, as funções ficam em definition/functions.tmdl |
| Model Explorer | Nó Functions: criar e editar pela barra de fórmulas |
No Model Explorer, o botão direito na função oferece Consultas rápidas (Evaluate, Define and evaluate, Define all functions in this model) e Script TMDL to.
Regras de nome
- Função: letras, números,
_e ponto para agrupar (Vendas.Margem,Calendario.DiasUteis). Sem espaço, sem começar ou terminar com ponto, sem dois pontos seguidos, sem repetir nome de função nativa ou palavra reservada (measure,function,define). - Parâmetro: letras, números e
_. Sem ponto e sem palavra reservada.
2. Anatomia
DEFINE
/// Aplica imposto sobre um valor.
/// @param {NUMERIC} valor - Valor antes do imposto
/// @param {NUMERIC} [aliquota] - Alíquota opcional; padrão 0,1 (10%)
/// @returns O valor com imposto
FUNCTION Fiscal.ComImposto =
( valor : NUMERIC, aliquota : NUMERIC = 0.1 ) =>
valor * ( 1 + aliquota )
EVALUATE
ROW (
"Padrão", Fiscal.ComImposto ( 100 ),
"Alíquota 20%", Fiscal.ComImposto ( 100, 0.2 )
)
-- 110 e 120- Descrição:
///acima da função, com as tags JSDoc@parame@returns. Comentário com//ou/* */não aparece no IntelliSense. - Parâmetros: de 0 a 256. Cada um aceita
[tipo] [subtipo] [modo], todos opcionais. Sem nada, o parâmetro valeAnyVal val. - Parâmetro opcional:
= <expressão padrão>torna o argumento opcional. Dá para pular no meio (MinhaFuncao ( 1, , 3 )); o mínimo de argumentos é definido pelo último parâmetro obrigatório. A expressão padrão só enxerga o que existe onde a função foi definida e não pode usar outro parâmetro opcional.
3. Tipos de parâmetro
| Família | Tipo | Aceita | Modo |
|---|---|---|---|
| Valor | ANYVAL | Escalar ou tabela. É o padrão quando o tipo é omitido | val (padrão) ou expr |
| Valor | SCALAR | Escalar, com subtipo opcional | val (padrão) ou expr |
| Valor | TABLE | Tabela ou expressão de tabela | val (padrão) ou expr |
| Expressão | ANYREF | Qualquer referência — equivale a não restringir o tipo de expressão | sempre expr |
| Expressão | MEASUREREF | Referência a medida | sempre expr |
| Expressão | COLUMNREF | Referência a coluna | sempre expr |
| Expressão | TABLEREF | Referência a tabela | sempre expr |
| Expressão | CALENDARREF | Referência a calendário | sempre expr |
- Tipos de valor fazem conversão implícita (
"5"vira 5 numINT64). Tipos de expressão não fazem. - Os tipos
MEASUREREF,COLUMNREF,TABLEREFeCALENDARREFchegaram em março/2026; material mais antigo só citaANYREF. - 💡 Use o tipo mais específico que resolve: o IntelliSense e a validação passam a recusar o argumento errado já na chamada.
Subtipos de SCALAR — declarar o subtipo já implica SCALAR:
| Subtipo | Aceita |
|---|---|
INT64 | Número inteiro |
DECIMAL | Decimal fixo (moeda, 4 casas) |
DOUBLE | Decimal de ponto flutuante |
NUMERIC | Qualquer um dos três acima |
STRING | Texto |
DATETIME | Data/hora |
BOOLEAN | TRUE/FALSE |
VARIANT | Qualquer escalar |
DEFINE
/// Converte para inteiro, arredondando.
FUNCTION Tipo.ParaInteiro = ( x : INT64 ) => x
EVALUATE
{ Tipo.ParaInteiro ( 3.4 ), Tipo.ParaInteiro ( 3.5 ), Tipo.ParaInteiro ( "5" ) }
-- 3, 4, 5 (texto não numérico dá erro)4. VAL × EXPR: onde o argumento é calculado
| Modo | Quando calcula | Herda do chamador |
|---|---|---|
val | Uma vez, antes de entrar na função | Contexto de linha e de filtro |
expr | Dentro da função, onde o parâmetro aparece — pode ser várias vezes, e em outro contexto | Só o contexto de filtro |
DEFINE
/// Recebe a tabela já filtrada: o ALL de dentro não tem efeito.
FUNCTION Contagem.LinhasAgora = ( t : TABLE VAL ) =>
COUNTROWS ( CALCULATETABLE ( t, ALL ( 'Calendário' ) ) )
/// Recebe a expressão: o ALL de dentro remove o filtro de ano.
FUNCTION Contagem.LinhasDepois = ( t : TABLE EXPR ) =>
COUNTROWS ( CALCULATETABLE ( t, ALL ( 'Calendário' ) ) )
EVALUATE
ROW (
"VAL (só 2025)", CALCULATE ( Contagem.LinhasAgora ( Vendas ), 'Calendário'[Ano] = 2025 ),
"EXPR (todos os anos)", CALCULATE ( Contagem.LinhasDepois ( Vendas ), 'Calendário'[Ano] = 2025 )
)A consequência prática — transição de contexto. Um parâmetro expr
não herda o contexto de linha. Dentro de um iterador:
- Referência de medida (
MEASUREREF, ou uma medida passada aANYREF) faz a transição de contexto sozinha, como toda medida. - Expressão como
SUM ( Vendas[Valor Venda] )não faz: semCALCULATE, ela devolve o total geral em cada linha.
DEFINE
/// Soma a medida dos N maiores clientes.
/// @param {MEASUREREF} medida - Medida a ranquear e somar
/// @param {INT64} [n] - Quantidade de clientes; padrão 10
FUNCTION Vendas.TopClientesMedida =
( medida : MEASUREREF, n : INT64 = 10 ) =>
SUMX ( TOPN ( n, VALUES ( Cliente[Nome do Cliente] ), medida ), medida )
/// Aceita qualquer expressão escalar: o CALCULATE garante a transição
/// de contexto em cada cliente.
/// @param {SCALAR} valorExpr - Medida ou expressão a ranquear e somar
/// @param {INT64} [n] - Quantidade de clientes; padrão 10
FUNCTION Vendas.TopClientes =
( valorExpr : SCALAR EXPR, n : INT64 = 10 ) =>
SUMX (
TOPN ( n, VALUES ( Cliente[Nome do Cliente] ), CALCULATE ( valorExpr ) ),
CALCULATE ( valorExpr )
)
EVALUATE
ROW (
"Top 10 (medida)", Vendas.TopClientesMedida ( [Total de Vendas] ),
"Top 5 (expressão)", Vendas.TopClientes ( SUM ( Vendas[Valor Venda] ), 5 )
)💡 Convenção da casa: parâmetro expr termina em Expr (valorExpr),
para quem chama saber que a expressão será calculada dentro da função.
5. Checagem de tipo e funções auxiliares
Para aceitar tipos diferentes ou validar a entrada, teste o valor no
corpo da função. Em parâmetro expr, a checagem acontece quando o
parâmetro é usado, não na chamada.
| Categoria | Funções |
|---|---|
| Numérico | ISNUMERIC, ISNUMBER |
| Inteiro | ISINT64, ISINTEGER |
| Decimal fixo | ISDECIMAL, ISCURRENCY |
| Ponto flutuante | ISDOUBLE |
| Texto | ISSTRING, ISTEXT |
| Lógico | ISBOOLEAN, ISLOGICAL |
| Data/hora | ISDATETIME |
DEFINE
/// Tamanho do texto, ou BLANK se não for texto.
FUNCTION Texto.Tamanho = ( s ) =>
IF ( ISSTRING ( s ), LEN ( s ), BLANK () )
EVALUATE
{ Texto.Tamanho ( "Power BI" ), Texto.Tamanho ( 123 ) }
-- 8 e BLANKTABLEOF ( referência ): devolve a tabela de uma coluna, medida ou calendário — útil comANYREF/COLUMNREFpara descobrir sobre qual tabela iterar.NAMEOF ( referência ): devolve o nome do objeto como texto.INFO.USERDEFINEDFUNCTIONS (): lista as funções do modelo com todos os metadados (exige permissão de escrita).INFO.FUNCTIONS ( "ORIGIN", "2" )traz só nome e poucos dados.
6. Onde usar
| Onde | Exemplo | Cuidado |
|---|---|---|
| Medida | Total de Vendas c/ Imposto = Fiscal.ComImposto ( [Total de Vendas] ) | — |
| Coluna calculada | Valor c/ Imposto = CONVERT ( Fiscal.ComImposto ( Vendas[Valor Venda] ), CURRENCY ) | A função precisa devolver sempre o mesmo tipo; fixe com CONVERT |
| Cálculo visual | Valor c/ Imposto = Fiscal.ComImposto ( [Valor Venda] ) | Só enxerga campos do visual; sem IntelliSense para UDF |
| Outra UDF | FUNCTION Fiscal.ComImpostoEDesconto = ( valor : NUMERIC, desconto : NUMERIC ) => Fiscal.ComImposto ( valor - desconto ) | Sem recursão |
| Cadeia de formato dinâmica | Na medida, Formato → Dinâmico, expressão Formato.Escala ( SELECTEDMEASURE () ) | A medida continua numérica (gráficos funcionam). No visual, deixe Unidades de exibição em Nenhum, senão o visual reescala por cima. |
💡 Uma função de formato substitui a mesma lógica copiada em cada medida: Total de Vendas, Margem e Custo passam a usar uma linha só. Veja Formato.Escala na Code Library UDF DAX.
7. Limitações
- Sem recursão (nem mútua), sem sobrecarga e sem declarar tipo de retorno.
- Sem descrição por parâmetro no modelo (a tag
@paramdocumenta no IntelliSense). - Não dá para ocultar a função, colocar em pasta de exibição nem traduzir.
- Não funciona em modelo sem tabelas.
- Em conexão dinâmica, as funções do modelo de origem não aparecem no Model Explorer; medidas de relatório podem chamá-las, mas sem IntelliSense. Em modelo composto, medidas do modelo não chamam UDF do modelo de origem.
- ⚠️ Segurança em nível de objeto (OLS) não passa para a função. Uma função que usa uma medida protegida não fica protegida; para quem não tem acesso, a medida simplesmente não existe. Não exponha objetos protegidos em nomes ou descrições de função.
- Nome sem tabela (
[Valor]) é lido como medida: evite referência de coluna sem a tabela dentro de UDF. - Parâmetro
exprque não é usado no corpo nunca é calculado. - A função não pode devolver um
enum(os argumentos fixos de funções nativas).
Funções prontas e documentadas: Code Library UDF DAX. Como testar e gravar na DAX Query View: DAX Query.