Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Observação
DAX As funções definidas pelo usuário estão atualmente em versão prévia.
DAX UDFs (funções definidas pelo usuário) permitem empacotar DAX lógica e reutilizá-la como qualquer outra DAX função. As UDFs introduzem uma nova FUNCTION palavra-chave, parâmetros opcionais (escalar, tabela e referências) e auxiliares de verificação de tipos que tornam a criação mais segura e clara. Depois de definir uma UDF, você pode usá-la em uma medida, coluna calculada, cálculo visual ou até mesmo outras funções definidas pelo usuário. Os usuários podem centralizar regras de negócios, melhorar a manutenção e desenvolver cálculos com segurança ao longo do tempo. As funções são objetos de modelo de primeira classe que você pode criar e gerenciar na visualização de consulta e no
Habilitar funções definidas pelo usuário
Para experimentar UDFs na área de trabalho:
- Vá para Arquivo > Opções e Configurações > Opções.
- Selecione recursos de visualização e verifique DAX as funções definidas pelo usuário.
- Selecione OK e reinicie o Power BI Desktop.
Definir e gerenciar funções definidas pelo usuário
Há vários locais para definir e gerenciar funções:
- DAX Exibição de consulta (DQV). Definir e modificar funções no DQV. O DQV também inclui consultas rápidas no menu de contexto (Avaliar, Definir e Avaliar, e Definir todas as funções do modelo) para ajudá-lo a testar e gerenciar UDFs rapidamente.
- Exibição TMDL. UDFs também podem ser criados e editados no TMDL. O modo de exibição TMDL também inclui Script TMDL para do menu de contexto.
- Gerenciador de modelos. As funções existentes podem ser exibidas no nó Funções no Explorador de Modelos.
Ao definir uma UDF, siga estes requisitos de nomenclatura:
Nomes de função:
- Precisa ser bem-definido e exclusivo dentro do modelo.
- Pode incluir períodos (pontos) para espaçamento de nomes (por exemplo, Microsoft.PowerBI.MyFunc). Não é possível iniciar ou terminar com um período ou ter períodos consecutivos.
- Além dos períodos, os nomes só podem conter caracteres alfanuméricos ou sublinhados. Nenhum espaço ou caracteres especiais permitidos.
- Não deve entrar em conflito com funções internas DAX ou palavras reservadas (por exemplo, medida, função, definição).
Nomes de parâmetro:
- Só pode conter caracteres alfanuméricos ou sublinhados. Períodos não são permitidos.
- Não deve ser uma palavra reservada.
Usando DAX o modo de exibição de consulta
Você pode definir, atualizar e avaliar funções definidas pelo usuário na DAX exibição de consulta. Para obter informações adicionais sobre o modo DAX de exibição de consulta, consulte DAX.
Formulário geral
DEFINE
/// Optional description above the function
FUNCTION <FunctionName> = ( [ParameterName]: [ParameterType], ... ) => <FunctionBody>
Dica
Use /// para descrições de função. Os comentários de linha única (//) ou de várias linhas (/* */) não aparecerão nas descrições de função do IntelliSense.
Exemplo: Função fiscal simples
DEFINE
/// AddTax takes in amount and returns amount including tax
FUNCTION AddTax =
( amount : NUMERIC ) =>
amount * 1.1
EVALUATE
{ AddTax ( 10 ) }
// Returns 11
Salvando no modelo de dados
Para salvar um UDF da visualização de consulta DAX para o modelo:
- Clique em Atualizar modelo com alterações para salvar todas as UDFs na consulta.
- Ou clique em Atualizar modelo: adicione uma nova função acima da função definida para salvar um único UDF.
Usando o modo de exibição TMDL
Você pode definir e/ou atualizar funções definidas pelo usuário no modo de exibição TMDL. Para obter informações adicionais sobre o modo de exibição TMDL, consulte o modo de exibição TMDL.
Formulário geral
createOrReplace
/// Optional description above the function
function <FunctionName> = ( [ParameterName]: [ParameterType], ... ) => <FunctionBody>
Exemplo: Função fiscal simples
createOrReplace
/// AddTax takes in amount and returns amount including tax
function AddTax =
(amount : NUMERIC) =>
amount * 1.1
Salvando no modelo de dados
Clique no botão Aplicar na parte superior da exibição para salvar todas as UDFs no script no modelo.
Usando o script TMDL em um projeto do Power BI
UDFs também são incluídos no script TMDL de modelo semântico ao usar um projeto do Power BI. Eles podem ser encontrados na functions.tmdl pasta de definição .
Usando o Gerenciador de Modelos
Você pode exibir todas as funções definidas pelo usuário no modelo do Gerenciador de Modelos no nó Funções. Para obter informações adicionais sobre o Gerenciador de Modelos, consulte o Gerenciador de Modelos.
No DAX modo de exibição de consulta, você pode usar consultas rápidas no menu de clique com o botão direito do mouse de um UDF no Gerenciador de Modelos para definir e avaliar facilmente as funções.
No modo de exibição TMDL, você pode arrastar e soltar funções na tela ou usar o Script TMDL no menu de clique com o botão direito do mouse de um UDF no Gerenciador de Modelos para gerar scripts.
Usando DMVs para inspecionar UDFs
Você pode inspecionar UDFs em seu modelo usando DMVs ( Exibições de Gerenciamento Dinâmico ). Essas exibições permitem que você consulte informações sobre funções, incluindo UDFs.
Você pode usar a função INFO.FUNCTIONS para inspecionar as UDFs no modelo. Para restringir o resultado somente a UDFs, especifique o ORIGIN parâmetro como 2.
EVALUATE INFO.FUNCTIONS("ORIGIN", "2")
Essa consulta retorna uma tabela de todas as UDFs atualmente no modelo, incluindo seu nome, descrição e metadados associados.
Usando uma função definida pelo usuário
Depois que um UDF é definido e salvo no modelo, você pode chamá-lo de medidas, colunas calculadas, cálculos visuais e outros UDFs. Isso funciona da mesma forma que chamar funções integradas DAX.
Invocando uma UDF em uma medida
Use uma UDF em uma medida para aplicar a lógica reutilizável com contexto de filtro completo.
Total Sales with Tax = AddTax ( [Total Sales] )
A medida de exemplo é mostrada na tabela abaixo:
Chamando uma UDF em uma coluna calculada
UDFs podem ser usados em uma coluna calculada para aplicar lógica reutilizável a cada linha de uma tabela.
Observação
Ao usar uma UDF em uma coluna calculada, verifique se a função retorna um escalar de um tipo consistente. Consulte Parâmetros para obter mais informações. Se necessário, converta o resultado no tipo desejado usando CONVERT ou funções semelhantes.
Sales Amount with Tax = CONVERT ( AddTax ( 'Sales'[Sales Amount] ), CURRENCY )
Podemos ver esta medida de exemplo usada na tabela abaixo:
Chamando uma UDF em um cálculo visual
Você pode usar UDFs em um cálculo visual para aplicar lógica diretamente à visualização. Para obter informações adicionais sobre cálculos visuais, consulte Cálculos Visuais.
Observação
Os cálculos visuais operam apenas em campos presentes no visual. Eles não podem acessar objetos de modelo que não fazem parte do visual e você não pode passar objetos de modelo (como colunas ou medidas que não estão no visual) para uma UDF neste contexto.
Sales Amount with Tax = AddTax ( [Sales Amount] )
Podemos ver esta medida de exemplo na tabela abaixo:
Chamando uma UDF em outra UDF
Você pode encadear UDFs chamando uma função de outra. Neste exemplo, definimos nossa UDF simples AddTax e a chamamos em outra UDF, AddTaxAndDiscount.
DEFINE
/// AddTax takes in amount and returns amount including tax
FUNCTION AddTax =
( amount : NUMERIC ) =>
amount * 1.1
FUNCTION AddTaxAndDiscount =
(
amount : NUMERIC,
discount : NUMERIC
) =>
AddTax ( amount - discount )
EVALUATE
{ AddTaxAndDiscount ( 10, 2 ) }
// Returns 8.8
Parâmetros
DAX UDFs podem aceitar zero ou mais parâmetros. Ao definir parâmetros para uma UDF, você pode, opcionalmente, especificar dicas de tipo para cada parâmetro:
-
Tipo: que tipo de valor o parâmetro aceita (
AnyVal, ,ScalarTableouAnyRef). -
Subtipo (somente para tipo escalar): o tipo de dados escalar específico (
Variant, ,Int64,Decimal,Double,String,DateTime,BooleanouNumeric). -
ParameterMode: quando o argumento é avaliado (
valouexpr).
As dicas de tipo estão na forma: [type] [subtype] [parameterMode]
Você pode incluir todas, algumas ou nenhuma dessas dicas de tipo para cada parâmetro para tornar suas funções mais seguras e previsíveis em sites de chamada. Se você omitir tudo e apenas escrever o nome do parâmetro, ele se comporta como AnyVal val, o que significa que o argumento será avaliado imediatamente no momento da solicitação. Isso é útil para funções simples.
Tipo
O tipo define a categoria do argumento que seu parâmetro aceita e se ele é passado como um valor ou uma expressão.
Há duas famílias de tipos em DAX parâmetros UDF: tipos de valor e tipos de expressão:
-
Tipos de valor: esse argumento é avaliado imediatamente (avaliação ansiosa) quando a função é chamada e o valor resultante é passado para a função.
-
AnyVal: aceita um escalar ou uma tabela. Esse é o padrão se você omitir o tipo de um parâmetro. -
Scalar: aceita um valor escalar (além disso, pode adicionar um subtipo). -
Table: Aceita uma tabela.
-
-
Tipos de expressão: esse argumento passa uma expressão não avaliada (avaliação lenta). A função decide quando e em qual contexto avaliá-la. Isso é necessário para parâmetros de referência e útil quando você precisa controlar o contexto de filtro (por exemplo, dentro CALCULATE).
expros tipos podem ser referências a uma coluna, tabela, calendário ou medida.-
AnyRef: aceita uma referência (uma coluna, uma tabela, um calendário ou uma medida).
-
Subtipo
O subtipo permite definir um tipo de dados específico Scalar . Se você definir um subtipo, não precisará definir explicitamente o parâmetro como um Scalar tipo, isso será assumido automaticamente.
Os subtipos são:
-
Variant: aceita qualquer escalar. -
Int64: Aceita um número inteiro. -
Decimal: aceita uma decimal de precisão fixa (como Moeda ou Dinheiro). -
Double: aceita uma decimal de ponto flutuante. -
String: aceita texto. -
DateTime: aceita data/hora. -
Boolean: aceita TRUE/FALSE. -
Numeric: aceita qualquer valor numérico (Int64ouDecimalDoublesubtipos)
ModoDeParâmetro
ParameterMode controla quando e onde a expressão de parâmetro é avaliada. Estes são:
-
val(avaliação ansiosa): a expressão é avaliada uma vez antes de invocar a função. Em seguida, o valor resultante é passado para a função. Isso é comum para entradas escalares ou de tabela simples. Esse é o padrão se você omitir parameterMode para um parâmetro. -
expr(avaliação lenta): a expressão é avaliada dentro da função, potencialmente em um contexto diferente (por exemplo, contexto de linha ou contexto de filtro) e possivelmente várias vezes se referenciada várias vezes ou dentro de iterações. Isso é necessário para parâmetros de referência e útil quando você precisa controlar o contexto de avaliação.
O Scalar tipo pode usar ou val ou expr. Use val quando quiser que o escalar seja avaliado uma vez no contexto do chamador. Use expr quando quiser adiar a avaliação e, possivelmente, aplicar o contexto dentro da função.
Veja exemplo: Parâmetro de tabela como exemplo.
O AnyRef tipo deve ser expr porque as suas referências (colunas, tabelas, medidas etc.) precisam ser avaliadas no contexto da função.
Exemplo: conversão de tipo
DEFINE
/// returns x cast to an Int64
FUNCTION CastToInt = (
x : SCALAR INT64 VAL
) =>
x
EVALUATE
{ CastToInt ( 3.4 ), CastToInt ( 3.5 ), CastToInt ( "5" ) }
// returns 3, 4, 5
Isso usa um Scalar tipo, Int64 subtipo e val parameterMode para arredondamento previsível e coerção de texto para número, além de garantir que todas as expressões sejam avaliadas imediatamente. Você também pode conseguir isso apenas incluindo o Int64 subtipo, conforme visto no exemplo abaixo. Cadeias de caracteres não numéricas resultarão em um erro.
DEFINE
/// returns x as an Int64
FUNCTION CastToInt = (
x : INT64
) =>
x
EVALUATE
{ CastToInt ( 3.4 ), CastToInt ( 3.5 ), CastToInt ( "5" ) }
// returns 3, 4, 5
Exemplo: Parâmetro de tabela (valor vs expressão)
Para ilustrar como o parâmetro UDF parameterMode afeta o contexto de filtro, considere duas funções que contam as linhas na tabela 'Vendas'. Ambos usam CALCULATETABLE(t, ALL('Date')) em seus corpos, mas um parâmetro é declarado como uma val (avaliação imediata) e o outro como expr (avaliação preguiçosa):
DEFINE
/// Table val: receives a materialized table, context can't be changed
FUNCTION CountRowsNow = (
t : TABLE VAL
) =>
COUNTROWS ( CALCULATETABLE ( t, ALL ( 'Date' ) ) )
/// Table expr: receives an unevaluated expression, context CAN be changed
FUNCTION CountRowsLater = (
t : TABLE EXPR
) =>
COUNTROWS ( CALCULATETABLE ( t, ALL ( 'Date' ) ) )
EVALUATE
{
CALCULATE ( CountRowsNow ( 'Sales' ), 'Date'[Fiscal Year] = "FY2020" ),
CALCULATE ( CountRowsLater ( 'Sales' ), 'Date'[Fiscal Year] = "FY2020" )
}
// returns 84285, 121253
CountRowsNow retorna a contagem de vendas somente para o ano fiscal de 2020. A tabela 'Vendas' já está filtrada pelo ano antes da inserção da função, portanto ALL('Date'), dentro da função, não tem efeito.
CountRowsLater retorna o número de vendas para todos os anos. A função recebe uma expressão de tabela não avaliada e a avalia sob ALL('Date'), removendo o filtro de ano externo.
Verificação de tipo
A verificação de tipo em UDFs pode ser feita com funções de verificação de tipo novas e existentes que você pode chamar dentro do corpo da função para confirmar o tipo de runtime de parâmetros passados. Isso permite que as UDFs usem controle de contexto, validem parâmetros antecipadamente, normalizem entradas antes do cálculo.
Observação
Para parâmetros no modo parameterMode, as verificações de tipo ocorrem quando o parâmetro é referenciado no corpo da função (e não no momento em que a função é chamada).
Funções de verificação de tipo disponíveis
UDFs podem usar as funções a seguir para testar valores escalares. Cada retorno TRUE/FALSE dependendo se o valor fornecido é desse tipo.
| Categoria | Functions |
|---|---|
| Numeric | ISNUMERIC, ISNUMBER |
| Double | ISDOUBLE |
| Número inteiro | ISINT64, ISINTEGER |
| Decimal | ISDECIMAL, ISCURRENCY |
| String | ISSTRING, ISTEXT |
| booleano | ISBOOLEAN, ISLOGICAL |
| Data e hora | ISDATETIME |
Exemplo: verificar se o parâmetro é uma cadeia de caracteres
DEFINE
/// Returns the length of a string, or BLANK if not a string
FUNCTION StringLength = (
s
) =>
IF ( ISSTRING ( s ), LEN ( s ), BLANK () )
EVALUATE
{ StringLength ( "hello" ), StringLength ( 123 ) }
// Returns: 5, BLANK
Isso evita erros e permite que você decida como lidar com a entrada não cadeia de caracteres na função (neste exemplo, retorna BLANK).
Exemplo: aceitar vários tipos de parâmetro
DEFINE
/// Helper 1: get currency name by int64 key
FUNCTION GetCurrencyNameByKey = (
k : INT64
) =>
LOOKUPVALUE ( 'Currency'[Currency], 'Currency'[CurrencyKey], k )
/// Helper 2: get currency name by string code
FUNCTION GetCurrencyNameByCode = (
code : STRING
) =>
LOOKUPVALUE ( 'Currency'[Currency], 'Currency'[Code], code )
/// Accepts key (int64) or code (string) and returns the currency name
FUNCTION GetCurrencyName = (
currency
) =>
IF (
ISINT64 ( currency ),
GetCurrencyNameByKey ( currency ),
GetCurrencyNameByCode ( currency )
)
EVALUATE
{ GetCurrencyName ( 36 ), GetCurrencyName ( "USD" ) }
// returns "Euro", "US Dollar"
Este exemplo mostra como usar a verificação de tipo em UDFs para aceitar com segurança vários tipos de entrada e retornar um único resultado previsível.
GetCurrencyName usa um argumento, currencyque pode ser uma chave de moeda de número inteiro ou um código de moeda de texto. A função verifica o tipo de argumento com ISINT64. Se a entrada for um inteiro, ele chamará o auxiliar GetCurrencyNameByKey que pesquisa o nome da moeda com base na chave de moeda. Se a entrada não for um inteiro, ele chamará o auxiliar GetCurrencyNameByCode que pesquisa o nome da moeda com base no código de moeda.
Definir várias funções ao mesmo tempo
As UDFs permitem definir várias funções em uma única consulta ou script, facilitando a organização da lógica reutilizável. Isso é especialmente útil quando você deseja encapsular cálculos relacionados ou rotinas auxiliares juntos. As funções podem ser avaliadas em conjunto ou individualmente.
DEFINE
/// Multiplies two numbers
FUNCTION Multiply = (
a,
b
) =>
a * b
/// Adds two numbers and 1
FUNCTION AddOne = (
x,
y
) =>
x + y + 1
/// Returns a random integer between 10 and 100
FUNCTION RandomInt = () =>
RANDBETWEEN ( 10, 100 )
EVALUATE
{ Multiply ( 3, 5 ), AddOne ( 1, 2 ), RandomInt () }
// returns 15, 4, 98
Exemplo avançado: conversão de moeda flexível
Para mostrar como as DAX UDFs podem lidar com uma lógica mais complexa, examinaremos um cenário de conversão de moeda. Este exemplo utiliza verificação de tipos e funções aninhadas para converter um determinado valor em uma moeda-alvo, usando a taxa de câmbio média ou do final do dia para uma data específica.
createOrReplace
function ConvertDateToDateKey =
(
pDate: scalar variant
) =>
YEAR ( pDate ) * 10000 + MONTH ( pDate ) * 100 + DAY ( pDate )
function ConvertToCurrency =
(
pCurrency:scalar variant,
pDate: scalar variant,
pUseAverageRate: scalar boolean,
pAmount: scalar decimal
) =>
var CurrencyKey =
EVALUATEANDLOG (
IF (
ISINT64 ( pCurrency ),
pCurrency,
CALCULATE (
MAX ( 'Currency'[CurrencyKey] ),
'Currency'[Code] == pCurrency
)
)
, "CurrencyKey"
)
var DateKey =
EVALUATEANDLOG (
SWITCH (
TRUE,
ISINT64 ( pDate ), pDate,
ConvertDateToDateKey ( pDate )
)
, "DateKey"
)
var ExchangeRate =
EVALUATEANDLOG (
IF (
pUseAverageRate,
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
)
)
, "ExchangeRate"
)
var Result =
IF (
ISBLANK ( pCurrency ) || ISBLANK ( pDate ) || ISBLANK ( pAmount ),
BLANK (),
IF (
ISBLANK ( ExchangeRate ) ,
"no exchange rate available",
ExchangeRate * pAmount
)
)
RETURN Result
A ConvertToCurrency função aceita tipos de entrada flexíveis para moeda e data. Os usuários podem fornecer uma chave de moeda ou chave de data diretamente ou fornecer um código de moeda ou um valor de data padrão. A função verifica o tipo de cada entrada e a manipula adequadamente: se pCurrency for um número inteiro, ela é tratada como uma chave de moeda; caso contrário, a função assume um código de moeda e tenta resolver a chave correspondente.
pDate segue um padrão semelhante, se for um número inteiro, ele será tratado como uma chave de data; caso contrário, a função pressupõe que é um valor de data padrão e é convertida em uma chave de data usando a ConvertDateToDateKey função auxiliar. Se a função não puder determinar uma taxa de exchnage válida, ela retornará a mensagem "nenhuma taxa de câmbio disponível".
Essa lógica pode ser usada para definir uma medida, como Vendas Totais em Moeda Local.
Total Sales in Local Currency =
ConvertToCurrency (
SELECTEDVALUE ( 'Currency'[Code] ),
SELECTEDVALUE ( 'Date'[DateKey] ),
TRUE,
[Total Sales]
)
Opcionalmente, isso pode ser emparelhado com uma cadeia de caracteres de formato dinâmico para exibir o resultado no formato de moeda apropriado.
CALCULATE (
MAX ( 'Currency'[Format String] ),
'Currency'[Code] == SELECTEDVALUE ( 'Currency'[Code] )
)
Um resultado de exemplo pode ser visto na captura de tela abaixo.
Considerações e limitações
As funções definidas pelo usuário estão atualmente em versão prévia e, durante a visualização, lembre-se das seguintes considerações e limitações:
Geral:
Não é possível criar ou modelar DAX UDFs no Serviço.
Não é possível ocultar/remover um UDF no modelo.
Não é possível colocar UDFs em pastas de exibição.
Nenhum botão de "criar função" na faixa de opções.
Não é possível combinar UDFs com traduções.
Não há suporte para UDFs em modelos sem tabelas.
Não há consulta rápida "definir com referências" na visualização de consulta DAX.
Object-Level Security (OLS) não é transferida para funções ou vice-versa. Por exemplo, considere a seguinte função
Fque se refere à medidaMyMeasureprotegida:function F = () => [MyMeasure] + 42quando
MyMeasureé protegido usando segurança em nível de objeto, a função F não é automaticamente segura. SeFé executado em uma identidade sem acesso aMyMeasure, ele age como seMyMeasurenão existisse. É recomendável evitar a revelação de objetos seguros em nomes de função e descrições.
Definindo uma UDF:
- Não há suporte para recursão ou recursão mútua.
- Não há suporte para sobrecarga de função.
- Não há suporte para tipos de retorno explícitos.
Parâmetros UDF:
- Não há suporte para parâmetros opcionais.
- Não há suporte para descrições de parâmetro.
- UDFs não podem retornar um
enumvalor. As funções internas que aceitamenumvalores como parâmetros de função não poderão usar UDFs nesse contexto. - Parâmetros indefinidos da dica
exprde tipo não são avaliados.
Suporte do IntelliSense:
- Embora as UDFs possam ser usadas em modelos de conexão em tempo real ou de composição, não há suporte do IntelliSense.
- Embora UDFs possam ser usados em cálculos visuais, a barra de fórmulas de cálculos visuais não tem suporte do IntelliSense para UDFs.
- A visualização TMDL não possui suporte adequado do IntelliSense para UDFs.
Erros conhecidos
Os seguintes problemas são conhecidos no momento e podem afetar a funcionalidade:
- As referências a um objeto de modelo de tabela (por exemplo, medida, tabela, coluna), em uma UDF (Função Definida pelo Usuário), não são atualizadas automaticamente quando esses objetos são renomeados. Se você renomear um objeto do qual uma UDF depende, o corpo da função ainda conterá o nome antigo. Você deve editar manualmente a expressão UDF para atualizar todas as referências ao objeto renomeado.
- Determinados cenários avançados envolvendo UDFs podem resultar em inconsistências de analisador. Por exemplo, os usuários podem ver sublinhados vermelhos ou erros de validação ao passar colunas como
exprparâmetros ou usar referências de coluna não qualificadas.