Compartilhar via


Introdução

Visão geral

O Microsoft Power Query fornece uma experiência avançada de "obter dados" que abrange muitos recursos. Uma funcionalidade principal do Power Query é filtrar e combinar, ou seja, para "mash-up" dados de uma ou mais de uma coleção avançada de fontes de dados com suporte. Qualquer mashup de dados desse tipo é expresso usando a linguagem de fórmula do Power Query (informalmente conhecida como "M"). O Power Query inscreve documentos M em uma ampla gama de produtos da Microsoft, incluindo Excel, Power BI, Analysis Services e Dataverse, para habilitar o mashup de dados repetível.

Este documento fornece a especificação para M. Após uma breve introdução que visa criar alguma primeira intuição e familiaridade com o idioma, o documento aborda o idioma precisamente em várias etapas progressivas:

  1. A estrutura lexical define o conjunto de textos que são lexicamente válidos.

  2. Valores, expressões, ambientes e variáveis, identificadores e o modelo de avaliação formam os conceitos básicos da linguagem.

  3. A especificação detalhada dos valores, primitivos e estruturados, define o domínio de destino da linguagem.

  4. Os valores têm tipos, um tipo especial de valor, que caracterizam os tipos fundamentais de valores e carregam metadados adicionais específicos às formas de valores estruturados.

  5. O conjunto de operadores em M define quais tipos de expressões podem ser formadas.

  6. As funções, outro tipo de valores especiais, fornecem a base para uma biblioteca padrão avançada para M e permitem a adição de novas abstrações.

  7. Erros podem ocorrer ao aplicar operadores ou funções durante a avaliação da expressão. Embora os erros não sejam valores, há maneiras de lidar com erros que mapeiam erros de volta aos valores.

  8. Permitir que as expressões permitam a introdução de definições auxiliares usadas para criar expressões complexas em etapas menores.

  9. Se as expressões derem suporte à avaliação condicional.

  10. As seções fornecem um mecanismo de modularidade simples. (As seções ainda não são aproveitadas pelo Power Query.)

  11. Por fim, uma gramática consolidada coleta os fragmentos gramaticais de todas as outras seções deste documento em uma única definição completa.

Para teóricos da linguagem computacional: a linguagem de fórmula especificada neste documento é uma linguagem funcional quase pura, de ordem superior, tipada dinamicamente e parcialmente lenta.

Expressões e valores

O constructo central em M é a expressão. Uma expressão pode ser avaliada (computada), gerando um único valor.

Embora muitos valores possam ser escritos literalmente como uma expressão, um valor não é uma expressão. Por exemplo, a expressão 1 é avaliada como o valor 1; as expressões 1+1 são avaliadas como o valor 2. Essa distinção é sutil, mas importante. Expressões são receitas para avaliação; os valores são os resultados da avaliação.

Os exemplos a seguir ilustram os diferentes tipos de valores disponíveis em M. Como convenção, um valor é escrito usando o formulário literal no qual eles apareceriam em uma expressão que é avaliada como apenas esse valor. (Observe que indica o // início de um comentário que continua até o final da linha.)

  • Um valor primitivo é um valor de parte única, como um número, lógico, texto ou nulo. Um valor nulo pode ser usado para indicar a ausência de qualquer dado.

    123                  // A number
    true                 // A logical
    "abc"                // A text
    null                 // null value
    
  • Um valor de lista é uma sequência ordenada de valores. M dá suporte a listas infinitas, mas se gravadas como literais, as listas têm um comprimento fixo. Os caracteres { de chaves e } denotar o início e o fim de uma lista.

    {123, true, "A"}     // list containing a number, a logical, and 
                          //     a text 
    {1, 2, 3}            // list of three numbers 
    
  • Um registro é um conjunto de campos. Um campo é um par nome/valor em que o nome é um valor de texto exclusivo dentro do registro do campo. A sintaxe literal para valores de registro permite que os nomes sejam gravados sem aspas, um formulário também chamado de identificadores. O seguinte mostra um registro que contém três campos chamados "A", "B" e "C", que têm valores 1, e .23

    [ 
          A = 1,  
          B = 2,  
          C = 3 
    ]
    
  • Uma tabela é um conjunto de valores organizados em colunas (que são identificadas pelo nome) e linhas. Não há sintaxe literal para criar uma tabela, mas há várias funções padrão que podem ser usadas para criar tabelas de listas ou registros.

    Por exemplo:

    #table( {"A", "B"}, { {1, 2}, {3, 4} } ) 
    

    Isso cria uma tabela da seguinte forma:

    Imagem de uma tabela de exemplo no idioma da fórmula M.

  • Uma função é um valor que, quando invocado com argumentos, produz um novo valor. Uma função é escrita listando os parâmetros da função entre parênteses, seguidos pelo símbolo =>de entrada, seguido pela expressão que define a função. Essa expressão normalmente se refere aos parâmetros (por nome).

    (x, y) => (x + y) / 2`
    

Evaluation

O modelo de avaliação da linguagem M é modelado após o modelo de avaliação comumente encontrado em planilhas, em que a ordem de cálculo pode ser determinada com base nas dependências entre as fórmulas nas células.

Se você tiver escrito fórmulas em uma planilha como o Excel, poderá reconhecer que as fórmulas à esquerda resultam nos valores à direita quando calculados:

Capturas de tela das fórmulas à direita, resultando nos valores à esquerda.

Em M, partes de uma expressão podem referenciar outras partes da expressão por nome e o processo de avaliação determina automaticamente a ordem na qual as expressões referenciadas são calculadas.

Você pode usar um registro para produzir uma expressão equivalente ao exemplo de planilha anterior. Ao inicializar o valor de um campo, você pode consultar outros campos dentro do registro usando o nome do campo, conforme mostrado no exemplo a seguir:

[  
    A1 = A2 * 2,  
    A2 = A3 + 1,  
    A3 = 1  
]

A expressão anterior é equivalente ao exemplo a seguir (em que ambos são avaliados como valores iguais):

[  
    A1 = 4,  
    A2 = 2,  
    A3 = 1  
]

Os registros podem ser contidos ou aninhados dentro de outros registros. Você pode usar o operador de pesquisa ([]) para acessar os campos de um registro por nome. Por exemplo, o seguinte registro tem um campo chamado Sales contendo um registro e um campo chamado Total que acessa os campos e FirstHalf o SecondHalfSales registro:

[  
    Sales = [ FirstHalf = 1000, SecondHalf = 1100 ], 
    Total = Sales[FirstHalf] + Sales[SecondHalf] 
]

A expressão anterior é equivalente ao exemplo a seguir quando é avaliada:

[  
    Sales = [ FirstHalf = 1000, SecondHalf = 1100 ], 
    Total = 2100 
]

Os registros também podem ser contidos em listas. Você pode usar o operador de índice posicional ({}) para acessar um item em uma lista por seu índice numérico. Os valores em uma lista são referenciados usando um índice baseado em zero desde o início da lista. Por exemplo, os índices 0 e 1 são usados para referenciar o primeiro e o segundo itens na lista a seguir:

[ 
    Sales =  
        {  
            [  
                Year = 2007,  
                FirstHalf = 1000,  
                SecondHalf = 1100, 
                Total = FirstHalf + SecondHalf // 2100 
            ], 
            [  
                Year = 2008,  
                FirstHalf = 1200,  
                SecondHalf = 1300, 
                Total = FirstHalf + SecondHalf // 2500 
            ]  
        }, 
    TotalSales = Sales{0}[Total] + Sales{1}[Total] // 4600 
]

Expressões de membro de lista e registro (bem como expressões let) são avaliadas usando avaliação lenta, o que significa que elas são avaliadas apenas conforme necessário. Todas as outras expressões são avaliadas usando a avaliação ansiosa, o que significa que elas são avaliadas imediatamente quando encontradas durante o processo de avaliação. Uma boa maneira de pensar sobre isso é lembrar que avaliar uma lista ou expressão de registro retorna um valor de lista ou registro que se lembra de como seus itens de lista ou campos de registro precisam ser computados, quando solicitados (por operadores de pesquisa ou índice).

Functions

Em M, uma função é um mapeamento de um conjunto de valores de entrada para um único valor de saída. Uma função é gravada primeiro nomeando o conjunto necessário de valores de entrada (os parâmetros para a função) e, em seguida, fornecendo uma expressão que computa o resultado da função usando esses valores de entrada (o corpo da função) seguindo o símbolo goes-to (=>). Por exemplo:

(x) => x + 1                    // function that adds one to a value 
(x, y) =>  x + y                // function that adds two values

Uma função é um valor como um número ou um valor de texto. O exemplo a seguir mostra uma função que é o valor de um campo Adicionar, que é então invocado ou executado, de vários outros campos. Quando uma função é invocada, um conjunto de valores é especificado que são logicamente substituídos pelo conjunto necessário de valores de entrada dentro da expressão do corpo da função.

[ 
    Add = (x, y) => x + y,
    OnePlusOne = Add(1, 1),     // 2 
    OnePlusTwo = Add(1, 2)      // 3
]

Biblioteca

M inclui um conjunto comum de definições disponíveis para uso de uma expressão chamada biblioteca padrão ou apenas biblioteca , para abreviar. Essas definições consistem em um conjunto de valores nomeados. Os nomes de valores fornecidos por uma biblioteca estão disponíveis para uso em uma expressão sem terem sido definidos explicitamente pela expressão. Por exemplo:

Number.E                        // Euler's number e (2.7182...) 
Text.PositionOf("Hello", "ll")  // 2

Operadores

M inclui um conjunto de operadores que podem ser usados em expressões. Os operadores são aplicados a operandos para formar expressões simbólicas. Por exemplo, na expressão 1 + 2 os números 1 e 2 os operandos e o operador é o operador de adição (+).

O significado de um operador pode variar dependendo de que tipo de valores são seus operandos. Por exemplo, o operador de adição pode ser usado com outros tipos de valores além de números:

1 + 2                   // numeric addition: 3 
#time(12,23,0) + #duration(0,0,2,0) 
                        // time arithmetic: #time(12,25,0)

Outro exemplo de um operador com significado de operando dependendo é o operador de combinação (&):

"A" & "BC"              // text concatenation: "ABC" 
{1} & {2, 3}            // list concatenation: {1, 2, 3} 
[ a = 1 ] & [ b = 2 ]   // record merge: [ a = 1, b = 2 ]

Observe que alguns operadores não dão suporte a todas as combinações de valores. Por exemplo:

1 + "2"  // error: adding number and text isn't supported

Expressões que, quando avaliadas, encontram condições de operador indefinidas são avaliadas como erros.

Metadados

Metadados são informações sobre um valor associado a um valor. Os metadados são representados como um valor de registro, chamado de registro de metadados. Os campos de um registro de metadados podem ser usados para armazenar os metadados de um valor.

Cada valor tem um registro de metadados. Se o valor do registro de metadados não tiver sido especificado, o registro de metadados estará vazio (não tem campos).

Os registros de metadados fornecem uma maneira de associar informações adicionais a qualquer tipo de valor de forma discreta. Associar um registro de metadados a um valor não altera o valor ou seu comportamento.

Um valor y de registro de metadados está associado a um valor x existente usando a sintaxe x meta y. Por exemplo, o código a seguir associa um registro Rating de metadados e Tags campos ao valor "Mozart"de texto:

"Mozart" meta [ Rating = 5, Tags = {"Classical"} ]

Para valores que já carregam um registro de metadados não vazio, o resultado da aplicação de meta é o da computação da mesclagem de registros do registro existente e do novo registro de metadados. Por exemplo, as duas expressões a seguir são equivalentes umas às outras e à expressão anterior:

("Mozart" meta [ Rating = 5 ]) meta [ Tags = {"Classical"} ] 
"Mozart" meta ([ Rating = 5 ] & [ Tags = {"Classical"} ])

Um registro de metadados pode ser acessado para um determinado valor usando a Value.Metadata função. No exemplo a seguir, a expressão no ComposerRating campo acessa o registro de metadados do valor no Composer campo e acessa o Rating campo do registro de metadados.

[ 
    Composer = "Mozart" meta [ Rating = 5, Tags = {"Classical"} ], 
    ComposerRating = Value.Metadata(Composer)[Rating] // 5
]

Permitir expressão

Muitos dos exemplos mostrados até agora incluíram todos os valores literais da expressão no resultado da expressão. A let expressão permite que um conjunto de valores seja computado, atribuído nomes e, em seguida, usado em uma expressão subsequente que precede o in. Por exemplo, em nosso exemplo de dados de vendas, você pode fazer:

let 
    Sales2007 =  
        [  
            Year = 2007,  
            FirstHalf = 1000,  
            SecondHalf = 1100, 
            Total = FirstHalf + SecondHalf // 2100 
        ], 
    Sales2008 =  
        [  
            Year = 2008,  
            FirstHalf = 1200,  
            SecondHalf = 1300, 
            Total = FirstHalf + SecondHalf // 2500 
        ],
    TotalSales = Sales2007[Total] + Sales2008[Total]
in
    TotalSales  // 4600

O resultado da expressão acima é um valor numérico (4600) computado dos valores associados aos nomes Sales2007 e Sales2008.

Se expressão

A if expressão seleciona entre duas expressões com base em uma condição lógica. Por exemplo:

if 2 > 1 then
    2 + 2
else  
    1 + 1

A primeira expressão (2 + 2) será selecionada se a expressão lógica (2 > 1) for verdadeira e a segunda expressão (1 + 1) for selecionada se for false. A expressão selecionada (nesse caso 2 + 2) é avaliada e torna-se o resultado da if expressão (4).

Errors

Um erro é uma indicação de que o processo de avaliação de uma expressão não pôde produzir um valor.

Os erros são gerados por operadores e funções que encontram condições de erro ou usando a expressão de erro. Os erros são tratados usando a try expressão. Quando um erro é gerado, um valor é especificado que pode ser usado para indicar por que o erro ocorreu.

let Sales = 
    [ 
        Revenue = 2000, 
        Units = 1000, 
        UnitPrice = if Units = 0 then error "No Units"
                    else Revenue / Units 
    ], 
    UnitPrice = try Number.ToText(Sales[UnitPrice]),
    Result = "Unit Price: " & 
        (if UnitPrice[HasError] then UnitPrice[Error][Message]
        else UnitPrice[Value])
in
    Result

O exemplo acima acessa o Sales[UnitPrice] campo e formata o valor que produz o resultado:

"Unit Price: 2"

Se o Units campo tivesse sido zero, o UnitPrice campo teria gerado um erro, que teria sido tratado pelo try. O valor resultante teria sido:

"Unit Price: No Units"

Uma try expressão converte valores e erros adequados em um valor de registro que indica se a try expressão lidou com um erro ou não, e o valor adequado ou o registro de erro extraído ao manipular o erro. Por exemplo, considere a seguinte expressão que gera um erro e, em seguida, manipula-o imediatamente:

try error "negative unit count"

Essa expressão é avaliada para o seguinte valor de registro aninhado, explicando as [HasError]pesquisas de campo e [Error] , [Message]no exemplo anterior de preço unitário.

[ 
    HasError = true, 
    Error = 
        [ 
            Reason = "Expression.Error", 
            Message = "negative unit count", 
            Detail = null 
        ] 
]

Um caso comum é substituir erros por valores padrão. A try expressão pode ser usada com uma cláusula opcional otherwise para obter exatamente isso em uma forma compacta:

try error "negative unit count" otherwise 42 
// 42