Wprowadzenie

Omówienie

Dodatek Microsoft Power Query zapewnia zaawansowane środowisko "pobierania danych", które obejmuje wiele funkcji. Podstawową funkcją dodatku Power Query jest filtrowanie i łączenie, czyli łączenie danych "mash-up" z co najmniej jednej bogatej kolekcji obsługiwanych źródeł danych. Takie mashupy danych są wyrażane przy użyciu języka formuł Power Query (nieformalnie nazywanego "M"). Dodatek Power Query osadza dokumenty języka M w wielu produktach firmy Microsoft, w tym w programie Excel, usłudze Power BI, usługach Analysis Services i usłudze Dataverse, aby umożliwić powtarzalne łączenie danych.

Ten dokument zawiera specyfikację języka M. Po krótkim wprowadzeniu, które ma na celu zbudowanie pierwszej intuicji i znajomości języka, dokument obejmuje język dokładnie w kilku krokach postępowych:

  1. Struktura leksykalna definiuje zestaw tekstów, które są prawidłowe leksykalnie.

  2. Wartości, wyrażenia, środowiska i zmienne, identyfikatory i model oceny tworzą podstawowe pojęcia języka.

  3. Szczegółowa specyfikacja wartości, zarówno pierwotnych, jak i strukturalnych, definiuje domenę docelową języka.

  4. Wartości mają typy, sam rodzaj wartości, który charakteryzuje podstawowe rodzaje wartości i przenosi dodatkowe metadane specyficzne dla kształtów wartości strukturalnych.

  5. Zestaw operatorów w języku M definiuje, jakie rodzaje wyrażeń można utworzyć.

  6. Funkcje, inny rodzaj wartości specjalnych, stanowią podstawę bogatej standardowej biblioteki języka M i umożliwiają dodawanie nowych abstrakcji.

  7. Błędy mogą wystąpić podczas stosowania operatorów lub funkcji podczas obliczania wyrażenia. Chociaż błędy nie są wartościami, istnieją sposoby obsługi błędów mapujących błędy z powrotem na wartości.

  8. Wyrażenia let umożliwiają wprowadzenie definicji pomocniczych używanych do tworzenia złożonych wyrażeń w mniejszych krokach.

  9. Jeśli wyrażenia obsługują ocenę warunkową.

  10. Sekcje zapewniają prosty mechanizm modułowości. (Sekcje nie są jeszcze używane przez dodatek Power Query).

  11. Na koniec skonsolidowana gramatyka zbiera fragmenty gramatyki ze wszystkich pozostałych sekcji tego dokumentu w jedną kompletną definicję.

W przypadku teoretyków języka komputerowego: język formuł określony w tym dokumencie jest w większości czysty, wyższej kolejności, dynamicznie wpisany, częściowo leniwy język funkcjonalny.

Wyrażenia i wartości

Centralna konstrukcja w języku M to wyrażenie. Wyrażenie można ocenić (obliczone), dając pojedynczą wartość.

Chociaż wiele wartości można zapisywać dosłownie jako wyrażenie, wartość nie jest wyrażeniem. Na przykład wyrażenie 1 oblicza wartość 1. Wyrażenia są obliczane 1+1 na wartość 2. To rozróżnienie jest subtelne, ale ważne. Wyrażenia to przepisy na ocenę; wartości to wyniki oceny.

W poniższych przykładach przedstawiono różne rodzaje wartości dostępnych w języku M. Zgodnie z konwencją wartość jest zapisywana przy użyciu formularza literału, w którym będą one wyświetlane w wyrażeniu, które daje w wyniku tylko ową wartość. (Zwróć uwagę, że znak // wskazuje początek komentarza, który jest kontynuowany na końcu wiersza).

  • Wartość pierwotna jest wartością jednoczęściową, taką jak liczba, wartość logiczna, tekstowa lub null. Wartość null może służyć do wskazywania braku jakichkolwiek danych.

    123                  // A number
    true                 // A logical
    "abc"                // A text
    null                 // null value
    
  • Wartość listy jest uporządkowaną sekwencją wartości. Język M obsługuje listy nieskończone, ale jeśli jest zapisywany jako literał, listy mają stałą długość. Znaki nawiasu klamrowego { i } oznaczają początek i koniec listy.

    {123, true, "A"}     // list containing a number, a logical, and 
                          //     a text 
    {1, 2, 3}            // list of three numbers 
    
  • Rekord jest zestawem pól. Pole jest parą nazwa/wartość, w której nazwa jest wartością tekstową unikatową w rekordzie pola. Składnia literału dla wartości rekordów umożliwia pisanie nazw bez cudzysłowów, formularz nazywany również identyfikatorami. Poniżej przedstawiono rekord zawierający trzy pola o nazwach "A", "B" i "C", które mają wartości 1, 2i 3.

    [ 
          A = 1,  
          B = 2,  
          C = 3 
    ]
    
  • Tabela to zestaw wartości zorganizowanych w kolumny (które są identyfikowane według nazwy) i wierszy. Nie ma składni literału do tworzenia tabeli, ale istnieje kilka standardowych funkcji, których można użyć do tworzenia tabel na podstawie list lub rekordów.

    Przykład:

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

    Spowoduje to utworzenie tabeli o następującym kształcie:

    Image of an example table in the M formula language.

  • Funkcja to wartość, która po wywołaniu z argumentami generuje nową wartość. Funkcja jest zapisywana przez wyświetlenie listy parametrów funkcji w nawiasach, a następnie symbol =>przechodzi do , a następnie wyrażenie definiujące funkcję. To wyrażenie zwykle odnosi się do parametrów (według nazwy).

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

Ocena

Model oceny języka M jest modelowany po modelu oceny często spotykanym w arkuszach kalkulacyjnych, gdzie kolejność obliczeń można określić na podstawie zależności między formułami w komórkach.

Jeśli formuły zostały napisane w arkuszu kalkulacyjnym, takim jak program Excel, możesz rozpoznać formuły po lewej stronie w wyniku wartości po prawej stronie podczas obliczania:

Image of the formulas on the right resulting in the values on the left.

W języku M części wyrażenia mogą odwoływać się do innych części wyrażenia według nazwy, a proces oceny automatycznie określa kolejność, w której są obliczane przywoływane wyrażenia.

Możesz użyć rekordu, aby utworzyć wyrażenie, które jest równoważne poprzedniemu przykładowi arkusza kalkulacyjnego. Podczas inicjowania wartości pola można odwoływać się do innych pól w rekordzie przy użyciu nazwy pola w następujący sposób:

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

Powyższe wyrażenie jest równoważne z następującymi wartościami (w tym oba wyrażenia są obliczane na równe wartości):

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

Rekordy mogą być zawarte w innych rekordach lub zagnieżdżone. Aby uzyskać dostęp do pól rekordu według nazwy, możesz użyć operatora wyszukiwania ([]). Na przykład następujący rekord ma pole o nazwie Sales zawierające rekord, a pole o nazwie Total , które uzyskuje FirstHalf dostęp do pól i SecondHalf rekordu Sales :

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

Powyższe wyrażenie jest równoważne następującemu, gdy zostanie obliczone:

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

Rekordy mogą być również zawarte na listach. Możesz użyć operatora indeksu pozycyjnego ({}), aby uzyskać dostęp do elementu na liście według jego indeksu liczbowego. Wartości na liście są określane przy użyciu indeksu opartego na zerach od początku listy. Na przykład indeksy 0 i 1 są używane do odwołowania się do pierwszych i drugich elementów na poniższej liście:

[ 
    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 
]

Wyrażenia składowe listy i rekordów (a także wyrażenia let) są oceniane przy użyciu oceny leniwej, co oznacza, że są oceniane tylko zgodnie z potrzebami. Wszystkie inne wyrażenia są oceniane przy użyciu oceny chętnej, co oznacza, że są one oceniane natychmiast po napotkaniu podczas procesu oceny. Dobrym sposobem myślenia o tym jest pamiętanie, że ocena wyrażenia listy lub rekordu zwraca wartość listy lub rekordu, która sama pamięta, jak należy obliczyć jego elementy listy lub pola rekordu, gdy jest to wymagane (według operatorów odnośnika lub indeksu).

Funkcje

W języku M funkcja jest mapowaniem z zestawu wartości wejściowych na pojedynczą wartość wyjściową. Funkcja jest zapisywana przez najpierw nazewnictwo wymaganego zestawu wartości wejściowych (parametrów funkcji), a następnie podanie wyrażenia, które oblicza wynik funkcji przy użyciu tych wartości wejściowych (treść funkcji) po symbolu goes-to (=>). Przykład:

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

Funkcja jest wartością podobną do liczby lub wartości tekstowej. W poniższym przykładzie pokazano funkcję, która jest wartością pola Dodaj, które jest następnie wywoływane lub wykonywane z kilku innych pól. Po wywołaniu funkcji określony jest zestaw wartości, które są logicznie zastępowane wymaganym zestawem wartości wejściowych w wyrażeniu treści funkcji.

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

Biblioteka

Język M zawiera wspólny zestaw definicji dostępnych do użycia w wyrażeniu nazywanym biblioteką standardową lub po prostu biblioteką w skrócie. Te definicje składają się z zestawu nazwanych wartości. Nazwy wartości udostępnianych przez bibliotekę są dostępne do użycia w wyrażeniu bez jawnego zdefiniowania przez wyrażenie. Przykład:

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

Operatory

Język M zawiera zestaw operatorów, których można używać w wyrażeniach. Operatory są stosowane do operandów w celu tworzenia wyrażeń symbolicznych. Na przykład w wyrażeniu 1 + 2 liczby 1 i 2 są operandami, a operator jest operatorem dodawania (+).

Znaczenie operatora może się różnić w zależności od rodzaju wartości, jakie są jego operandy. Na przykład operator plus może być używany z innymi rodzajami wartości oprócz liczb:

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

Innym przykładem operatora z argumentem operand-w zależności od znaczenia jest operator kombinacji (&):

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

Należy pamiętać, że niektóre operatory nie obsługują wszystkich kombinacji wartości. Przykład:

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

Wyrażenia, które podczas oceny napotykają niezdefiniowane warunki operatora, są obliczane na błędy.

Metadane

Metadane to informacje o wartości skojarzonej z wartością. Metadane są reprezentowane jako wartość rekordu, nazywana rekordem metadanych. Pola rekordu metadanych mogą służyć do przechowywania metadanych dla wartości.

Każda wartość ma rekord metadanych. Jeśli wartość rekordu metadanych nie została określona, rekord metadanych jest pusty (nie zawiera pól).

Rekordy metadanych umożliwiają kojarzenie dodatkowych informacji z dowolną wartością w sposób nieprawdziwy. Skojarzenie rekordu metadanych z wartością nie powoduje zmiany wartości ani jej zachowania.

Wartość y rekordu metadanych jest skojarzona z istniejącą wartością x przy użyciu składni x meta y. Na przykład poniższy kod kojarzy rekord metadanych z polami Rating i Tags z wartością "Mozart"tekstową :

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

W przypadku wartości, które mają już niepusty rekord metadanych, wynikiem zastosowania meta jest obliczanie scalania rekordów istniejącego i nowego rekordu metadanych. Na przykład następujące dwa wyrażenia są równoważne sobie i poprzedniemu wyrażeniu:

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

Dostęp do rekordu metadanych dla danej wartości można uzyskać przy użyciu funkcji Value.Metadata . W poniższym przykładzie wyrażenie w ComposerRating polu uzyskuje dostęp do rekordu metadanych wartości w Composer polu, a następnie uzyskuje dostęp do Rating pola rekordu metadanych.

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

Wyrażenie Let

Wiele przedstawionych do tej pory przykładów uwzględniało wszystkie wartości literału wyrażenia w wyniku wyrażenia. Wyrażenie let umożliwia obliczanie zestawu wartości, przypisywanie im nazw, a następnie używanie ich w kolejnym wyrażeniu, które jest zgodne z .in Na przykład w naszym przykładzie danych sprzedaży można wykonać następujące czynności:

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

Wynikiem powyższego wyrażenia jest wartość liczbowa (4600), która jest obliczana z wartości powiązanych z nazwami Sales2007 i Sales2008.

Wyrażenie If

Wyrażenie if wybiera między dwoma wyrażeniami na podstawie warunku logicznego. Przykład:

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

Pierwsze wyrażenie (2 + 2) jest zaznaczone, jeśli wyrażenie logiczne (2 > 1) ma wartość true, a drugie wyrażenie (1 + 1) jest zaznaczone, jeśli jest to fałsz. Wybrane wyrażenie (w tym przypadku 2 + 2) jest oceniane i staje się wynikiem if wyrażenia (4).

błędy

Błąd wskazuje, że proces obliczania wyrażenia nie może wygenerować wartości.

Błędy są wywoływane przez operatory i funkcje występujące w warunkach błędu lub przy użyciu wyrażenia błędu. Błędy są obsługiwane przy użyciu try wyrażenia . Po wystąpieniu błędu zostanie określona wartość, która może służyć do wskazania przyczyny wystąpienia błędu.

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

Powyższy przykład uzyskuje dostęp do Sales[UnitPrice] pola i formatuje wartość generującą wynik:

"Unit Price: 2"

Units Gdyby pole miało wartość zero, UnitPrice pole spowodowałoby wystąpienie błędu, który zostałby obsłużony przez element try. Wynikowa wartość byłaby wtedy:

"No Units"

Wyrażenie try konwertuje odpowiednie wartości i błędy na wartość rekordu, która wskazuje, czy try wyrażenie obsłużyło błąd, czy nie, oraz odpowiednią wartość lub rekord błędu wyodrębniony podczas obsługi błędu. Rozważmy na przykład następujące wyrażenie, które zgłasza błąd, a następnie obsługuje je od razu:

try error "negative unit count"

To wyrażenie daje w wyniku następującą wartość zagnieżdżonego rekordu, objaśniając [HasError]wyszukiwania pól , [Error]i [Message] w poprzednim przykładzie ceny jednostkowej.

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

Typowym przypadkiem jest zastąpienie błędów wartościami domyślnymi. Wyrażenie try może być używane z klauzulą opcjonalną otherwise , aby osiągnąć tylko to w formie kompaktowej:

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