Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Observação
DAX As funções definidas pelo usuário estão atualmente em visualização.
DAX As funções definidas pelo usuário (UDFs) permitem que você empacote DAX a lógica e a reutilize como qualquer outra DAX função. Os UDFs introduzem uma nova FUNCTION palavra-chave, parâmetros opcionais (escalar, tabela e referências) e auxiliares de verificação de tipo que tornam a criação mais segura e clara. Depois de definir um UDF, você pode usá-lo em uma medida, coluna calculada, cálculo visual ou até mesmo outras funções definidas pelo usuário. Os usuários podem centralizar as regras de negócios, melhorar a capacidade de manutenção e evoluir os 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 no modo de exibição de consulta e noDAXmodo de exibição TMDL, e podem ser exibidos no Gerenciador de modelos no nó Funções.
Habilitar funções definidas pelo usuário
Para testar UDFs no Desktop:
- Vá para Opções de arquivo > e opções de configurações>.
- Selecione Visualizar recursos e verifique asDAX funções definidas pelo usuário.
- Selecione OK e reinicie o Power BI Desktop.
Definir e gerenciar funções definidas pelo usuário
Existem vários locais para definir e gerir funções:
- DAX modo de exibição de consulta (DQV). Defina e modifique funções no DQV. O menu de contexto do DQV também inclui consultas rápidas (Avaliar, Definir e avaliar, e Definir todas as funções neste modelo) para ajudá-lo a testar e gerenciar rapidamente as Funções Definidas pelo Usuário (UDFs).
- Visualização TMDL. UDFs também podem ser criados e editados em TMDL. A visualização TMDL também inclui o menu de contexto Script TMDL para.
- Explorador de modelos. As funções existentes podem ser visualizadas no nó Funções no Explorador de modelos.
Ao definir um UDF, siga estes requisitos de nomenclatura:
Nomes das funções:
- Deve ter uma boa estrutura e ser único dentro do modelo.
- Pode incluir pontos para espaços de nomes (por exemplo, Microsoft.PowerBI.MyFunc). Não pode começar ou terminar com um período ou ter períodos consecutivos.
- Além dos pontos, os nomes só podem conter caracteres alfanuméricos ou sublinhados. Não são permitidos espaços ou caracteres especiais.
- Não deve entrar em DAX conflito com funções incorporadas ou palavras reservadas (por exemplo, medida, função, definição).
Nomes dos parâmetros:
- Só pode conter caracteres alfanuméricos ou sublinhados. Não são permitidos períodos.
- Não deve ser uma palavra reservada.
Usando o DAX modo de exibição de consulta
Você pode definir, atualizar e avaliar funções definidas pelo usuário no DAX modo de exibição de consulta. Para obter informações adicionais sobre o DAX modo de exibição de consulta, consulte DAX modo de exibição de consulta.
Formulário geral
DEFINE
/// Optional description above the function
FUNCTION <FunctionName> = ( [ParameterName]: [ParameterType], ... ) => <FunctionBody>
Sugestão
Use /// para descrições de funções. Comentários de linha única (//) ou multilinha (/* */) 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
Guardar no modelo
Para guardar um UDF da vista de DAX consulta no 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 na visualização TMDL. Para obter informações adicionais sobre a visualização TMDL, consulte Visualizaçã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
Guardar no modelo
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ídas no script TMDL do modelo semântico ao utilizar um projeto Power BI. Eles podem ser encontrados dentro functions.tmdl da pasta de definição .
Usando o explorador de modelos
Você pode exibir todas as funções definidas pelo usuário no modelo no Gerenciador de modelos no nó Funções . Para obter informações adicionais sobre o Gerenciador de modelos, consulte Explorador de modelos.
No DAX modo de exibição de consulta, você pode usar consultas rápidas no menu do botão direito do mouse de um UDF no Gerenciador de modelos para definir e avaliar funções facilmente.
No modo de exibição TMDL, você pode arrastar e soltar funções na tela ou usar Script TMDL para no menu do botão direito do mouse de um UDF dentro do Gerenciador de modelos para gerar scripts.
Usando DMVs para inspecionar UDFs
Você pode inspecionar UDFs em seu modelo usando DMVs ( Dynamic Management Views ). 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 apenas 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 a partir de medidas, colunas calculadas, cálculos visuais e outros UDFs. Isso funciona exatamente da mesma forma que chamar funções integradas DAX.
Utilização de uma UDF numa medida
Use uma Função Definida pelo Usuário (UDF) numa medida para aplicar 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
As UDFs podem ser usadas em uma coluna calculada para aplicar lógica reutilizável a cada linha de uma tabela.
Observação
Ao usar um 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 para o tipo desejado usando CONVERT ou funções semelhantes.
Sales Amount with Tax = CONVERT ( AddTax ( 'Sales'[Sales Amount] ), CURRENCY )
Podemos ver este exemplo de medida usado na tabela abaixo:
Chamando uma UDF em um cálculo visual
Você pode usar UDFs num 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 só operam 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 estejam no visual) para um UDF nesse contexto.
Sales Amount with Tax = AddTax ( [Sales Amount] )
Podemos ver este exemplo de medida na tabela abaixo:
Chamando uma UDF em outra UDF
Você pode aninhar funções UDFs chamando uma função de outra. Neste exemplo, definimos a nossa UDF simples AddTax e chamamo-la 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 um UDF, você pode, opcionalmente, especificar dicas de tipo para cada parâmetro:
-
Tipo: que tipo de valor o parâmetro aceita (
AnyVal,Scalar,Table, ouAnyRef). -
Subtipo (apenas para tipo escalar): o tipo de dados escalares específico (
Variant,Int64,Decimal,Double,String,DateTime,Boolean, ouNumeric). -
ParameterMode: quando o argumento é avaliado (
valouexpr).
As anotações de tipo estão no formato: [type] [subtype] [parameterMode]
Você pode incluir todos, alguns ou nenhum destes tipos de sugestões para cada parâmetro, para tornar as suas funções mais seguras e previsíveis nos locais 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 é avaliado imediatamente no momento da chamada. Isso é útil para funções simples.
Tipo
Type define a categoria de argumento que seu parâmetro aceita e se ele é passado como um valor ou uma expressão.
Existem duas famílias de tipos nos DAX parâmetros UDF: tipos de valor e tipos de expressão:
-
Tipos de valor: este 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. Este é o padrão se você omitir o tipo para um parâmetro. -
Scalar: Aceita um valor escalar (pode adicionar adicionalmente um subtipo). -
Table: Aceita uma tabela.
-
-
Tipos de expressão: este argumento passa por uma expressão não avaliada (avaliação preguiçosa). A função decide quando e em que contexto avaliá-la. Isso é necessário para parâmetros de referência e útil quando você precisa controlar o contexto do 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, tabela, calendário ou 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á automaticamente assumido.
Os subtipos são:
-
Variant: Aceita qualquer escalar. -
Int64: Aceita um número inteiro. -
Decimal: Aceita um decimal de precisão fixa (como Moeda ou Dinheiro). -
Double: Aceita um número decimal em ponto flutuante. -
String: Aceita texto. -
DateTime: Aceita data/hora. -
Boolean: Aceita TRUE/FALSE. -
Numeric: Aceita qualquer valor numérico (Int64,Decimal, ouDoublesubtipos)
Modo de Parâmetro
ParameterMode controla quando e onde a expressão do parâmetro é avaliada. São eles:
-
val(avaliação ansiosa): A expressão é avaliada uma vez antes de invocar a função. O valor resultante é então passado para a função. Isso é comum para entradas escalares ou de tabela simples. Este é o padrão se você omitir parameterMode para um parâmetro. -
expr(avaliação preguiçosa): 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 tanto val como 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 contexto dentro da função. Consulte Exemplo: parâmetro Table como exemplo.
O AnyRef tipo deve ser expr como suas referências (colunas, tabelas, medidas, etc.) precisam ser avaliadas no contexto da função.
Exemplo: Tipo de fundição
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 com entusiasmo. Você também pode conseguir isso apenas incluindo o Int64 subtipo, como 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 Table (valor vs expressão)
Para ilustrar como o parameterMode do UDF afeta o contexto do filtro, considere duas funções que contam linhas na tabela 'Vendas'. Ambos usam CALCULATETABLE(t, ALL('Date')) nos seus corpos, mas um parâmetro é declarado como uma val (avaliação imediata) e o outro como expr (avaliação tardia):
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 exercício fiscal de 2020. A tabela 'Vendas' já é filtrada pelo ano antes de entrar na função, portanto ALL('Date'), dentro da função, não surte efeito.
CountRowsLater retorna a contagem total de vendas realizadas ao longo de todos os anos. A função recebe uma expressão de tabela não avaliada e a avalia em 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 tempo de execução dos parâmetros passados. Isso permite que UDFs usem controle de contexto, validem parâmetros antecipadamente, normalizem entradas antes do cálculo.
Observação
Para expr parâmetros parameterMode, as verificações de tipo ocorrem quando o parâmetro é referenciado no corpo da função (não no momento da chamada da função).
Funções de verificação de tipo disponíveis
UDFs podem usar as seguintes funções para testar valores escalares. Cada retorno TRUE/FALSE depende se o valor fornecido é desse tipo.
| Categoria | Funções |
|---|---|
| Numeric | ISNUMÉRICO,ISNUMBER |
| Double | ISDOUBLE |
| Número inteiro | ISINT64, ISINTEGER |
| Decimal | É_DECIMAL,É_MOEDA |
| Cordão | ISSTRING,ISTEXT |
| booleano | ISBOOLEAN,ISLOGICAL |
| Data e Hora | ISDATETIME |
Exemplo: Verifique 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 manipular a entrada não-string na função (neste exemplo, retorna BLANK).
Exemplo: Aceitar vários tipos de parâmetros
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, currency, que 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, ela chamará o auxiliar GetCurrencyNameByKey que procura o nome da moeda com base na chave de moeda. Se a entrada não for um número inteiro, ela chamará o auxiliar GetCurrencyNameByCode que procura o nome da moeda com base no código da 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 DAX as UDFs podem lidar com lógicas mais complexas, veremos um cenário de conversão de moeda. Este exemplo usa verificação de tipos e funções aninhadas para converter um determinado valor numa moeda de destino, usando a taxa de câmbio média ou a taxa de câmbio de fim de dia para uma determinada data.
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 valor de data padrão. A função verifica o tipo de cada entrada e manipula-a de acordo: se pCurrency for um número inteiro, é tratado 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, é tratado como uma chave de data; caso contrário, a função assume 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 câmbio válida, ela retornará a mensagem "nenhuma taxa de câmbio disponível".
Essa lógica pode ser usada para definir uma medida como Total de Vendas em Moeda Local.
Total Sales in Local Currency =
ConvertToCurrency (
SELECTEDVALUE ( 'Currency'[Code] ),
SELECTEDVALUE ( 'Date'[DateKey] ),
TRUE,
[Total Sales]
)
Isso pode ser opcionalmente 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 exemplo de resultado pode ser visto na imagem abaixo.
Considerações e limitações
As funções definidas pelo usuário estão atualmente em visualização e, durante a visualização, esteja ciente 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/reexibir um UDF no modelo.
Não é possível colocar UDFs em pastas de exibição.
Não há botão 'criar função' na faixa de opções.
Não é possível combinar UDFs com traduções.
UDFs não são suportados em modelos sem tabelas.
Não há consulta rápida de 'definir com referências' no DAX modo de exibição de consulta.
Segurança a Nível de Objeto (OLS) não se transfere para funções nem vice-versa. Por exemplo, considere a seguinte função
Fque se refere à medidaMyMeasuresegura:function F = () => [MyMeasure] + 42quando o
MyMeasureé assegurado usando segurança ao nível de objeto, a função F não é automaticamente assegurada. SeFcorrer sob uma identidade sem acesso aMyMeasure, comporta-se como seMyMeasurenão existisse. Recomendamos evitar revelar objetos seguros em nomes e descrições de funções.
Definindo uma UDF:
- Não há suporte para recursão ou recursão mútua.
- A sobrecarga de funções não é suportada.
- Os tipos de retorno explícito não são suportados.
Parâmetros UDF:
- Não há suporte para parâmetros opcionais.
- Não há suporte para descrições de parâmetros.
- UDFs não podem retornar um
enumvalor. As funções internas que aceitamenumvalores como seus parâmetros de função não poderão usar UDFs nesse contexto. - Os parâmetros desassociados da dica de tipo
exprnão são avaliados.
Suporte IntelliSense:
- Embora as UDFs possam ser usadas em modelos compostos ou de conexão ao vivo, não há suporte ao IntelliSense.
- Embora as UDFs possam ser usadas em cálculos visuais, a barra de fórmulas de cálculos visuais não tem suporte ao IntelliSense para UDFs.
- A vista TMDL não tem suporte apropriado de IntelliSense para UDFs.
Bugs conhecidos
Os seguintes problemas são atualmente conhecidos e podem afetar a funcionalidade:
- As referências a um objeto de modelo tabular (por exemplo, medida, tabela, coluna) em um UDF não são atualizadas automaticamente quando esses objetos são renomeados. Se você renomear um objeto do qual um 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.
- Certos cenários avançados envolvendo UDFs podem resultar em inconsistências do analisador. Por exemplo, os utilizadores podem ver sublinhados vermelhos ou erros de validação ao passar colunas como parâmetros de
exprou ao usar referências de coluna não qualificadas.