Einführung
Übersicht
Microsoft Power Query bietet leistungsstarke Features und Funktionen für das Abrufen von Daten. Eine zentrale Funktion von Power Query ist das Filtern und Kombinieren, also Daten aus mindestens einer umfangreichen Sammlung unterstützter Datenquellen zu kombinieren. Diese Mashups von Daten werden mithilfe der Power Query-Formelsprache ausgedrückt (informell auch „M“ genannt). Power Query kann M-Dokumente in eine Vielzahl von Microsoft-Produkten einbetten, einschließlich Excel, Power BI, Analysis Services und Dataverse, um ein wiederholbares Mashup von Daten zu ermöglichen.
Dieses Thema enthält die Spezifikation für M. Nachdem Sie sich in der kurzen Einführung allgemein mit der Sprache vertraut gemacht haben, wird die Sprache eingehender in mehreren aufeinander aufbauenden Artikeln behandelt:
Im Artikel Lexikalische Struktur werden die Textzeichen definiert, die lexikalisch zulässig sind.
Werte, Ausdrücke, Umgebungen, Variablen, Bezeichner und das Auswertungsmodell bilden die Grundkonzepte der Sprache.
In der ausführlichen Spezifikation der primitiven und strukturierten Werte wird die Zieldomäne der Sprache erläutert.
Werte haben Typen. Dabei handelt es sich wiederum um eine besondere Art von Wert, der sowohl den grundlegenden Wertetyp charakterisiert als auch zusätzliche Metadaten enthält, die für die Formen von strukturierten Werten typisch sind.
Die Operatoren in M bestimmen, welche Arten von Ausdrücken gebildet werden können.
Funktionen, ein weiterer spezieller Wertetyp, bilden die Grundlage für die umfangreiche Standardbibliothek von M und ermöglichen das Hinzufügen neuer Abstraktionen.
Fehler können auftreten, wenn Operatoren oder Funktionen bei der Auswertung von Ausdrücken angewendet werden. Obwohl es sich bei Fehlern nicht um Werte handelt, gibt es Methoden für die Fehlerbehandlung, bei denen Fehler auf Werte zurückgeführt werden.
let-Ausdrücke ermöglichen es, Hilfsdefinitionen einzuführen, mit denen sich komplexe Ausdrücke in kleineren Schritten erstellen lassen.
if-Ausdrücke ermöglichen die bedingte Auswertung.
Abschnitte stellen einen einfachen Modularitätsmechanismus bereit. (Abschnitte werden in Power Query noch nicht genutzt.)
Zuletzt werden in der konsolidierten Grammatik die grammatikalischen Komponenten aus allen vorherigen Abschnitten dieses Dokuments in einer einzelnen vollständigen Übersicht zusammengefasst.
Ein Hinweis für theoretische Wissenschaftler im Bereich Computersprachen: Die Formelsprache in diesem Dokument ist eine überwiegend reine, dynamisch typisierte funktionale Sprache der höheren Ordnung, in der teilweise nach dem Lazy-Evaluation-Prinzip ausgewertet wird.
Ausdrücke und Werte
Das zentrale Konstrukt in M sind Ausdrücke. Ein Ausdruck kann ausgewertet (berechnet) werden. Das Ergebnis ist ein einzelner Wert.
Obwohl viele Werte als Ausdruck geschrieben werden können, ist ein Wert kein Ausdruck. So wird beispielsweise der Ausdruck 1
zu dem Wert 1 ausgewertet und der Ausdruck 1+1
zum Wert 2. Dieser Unterschied ist fein, aber wichtig. Ausdrücke sind wichtig für die Auswertung; Werte sind die Ergebnisse der Auswertung.
In den folgenden Beispielen werden die unterschiedlichen Arten von Werten veranschaulicht, die in M verfügbar sind. Die Konvention lautet, dass Werte immer in dem literalen Format geschrieben werden, in dem sie in einem Ausdruck vorkommen würden, der zu genau diesem Wert ausgewertet wird. (Beachten Sie, dass //
den Anfang eines Kommentars angibt. Die Auskommentierung gilt bis zum Ende der Zeile.)
Ein primitiver Wert ist ein Einzelteilwert, wie beispielsweise eine Zahl, ein Wahrheitswert, Text oder NULL. Ein NULL-Wert kann verwendet werden, um das Fehlen von Daten anzuzeigen.
123 // A number true // A logical "abc" // A text null // null value
Ein Listenwert ist eine geordnete Sequenz von Werten. M unterstützt zwar unendliche Listen, wenn Listen jedoch als Literale geschrieben werden, haben Listen immer eine feste Länge. Die geschweiften Klammern
{
und}
bezeichnen den Anfang und das Ende einer Liste.{123, true, "A"} // list containing a number, a logical, and // a text {1, 2, 3} // list of three numbers
Ein Datensatz besteht aus mehreren Feldern. Ein Feld ist ein Name-Wert-Paar, wobei der Name ein Textwert ist, der innerhalb des Datensatzes des Feldes eindeutig ist. Die literale Syntax für Datensatzwerte ermöglicht es, die Namen ohne Anführungszeichen zu schreiben. Dieses Format wird auch Bezeichner genannt. Im folgenden Beispiel wird ein Datensatz gezeigt, der drei Felder namens „
A
“, „B
“ und „C
“ enthält, die die Werte1
,2
und3
enthalten.[ A = 1, B = 2, C = 3 ]
Eine Tabelle besteht aus einer Gruppe von Werten, die in Spalten (durch einen Namen gekennzeichnet) und Zeilen angeordnet sind. Es gibt keine literale Syntax für das Erstellen von Tabellen. Es sind jedoch mehrere Standardfunktionen verfügbar, mit denen sich Tabellen aus Listen oder Datensätzen erstellen lassen.
Beispiel:
#table( {"A", "B"}, { {1, 2}, {3, 4} } )
Mit dieser Funktion wird die folgende Tabelle erstellt:
Eine Funktion ist ein Wert, der einen neuen Wert erzeugt, wenn er mit Argumenten aufgerufen wird. In Funktionen werden die Parameter der Funktion in Klammern aufgelistet, gefolgt vom Pfeilsymbol
=>
und von dem Ausdruck, der die Funktion definiert. Dieser Ausdruck verweist in der Regel (namentlich) auf die Parameter.(x, y) => (x + y) / 2`
Auswertung
Das Auswertungsmodell der Sprache M ist nach dem in Tabellenkalkulationen üblichen Auswertungsmodell aufgebaut, bei dem die Reihenfolge der Berechnungen anhand von Abhängigkeiten zwischen den Formeln in den Zellen bestimmt wird.
Wenn Sie Formeln in eine Kalkulationstabelle wie Excel geschrieben haben, können Sie erkennen, dass die Formeln auf der linken Seite bei der Berechnung zu den Werten auf der rechten Seite führen:
In M können Teile eines Ausdrucks namentlich auf andere Teile des Ausdrucks verweisen. Die Reihenfolge, in der die referenzierten Ausdrücke berechnet werden, wird während des Auswertungsprozesses automatisch bestimmt.
Mithilfe eines Datensatzes lassen sich Ausdrücke erstellen, die dem obigen Beispiel der Kalkulationstabelle entsprechen. Bei der Initialisierung eines Feldwertes können Sie mithilfe des Feldnamens wie folgt auf andere Felder innerhalb des Datensatzes verweisen:
[
A1 = A2 * 2,
A2 = A3 + 1,
A3 = 1
]
Der obige Ausdruck entspricht dem folgenden (insofern, als dass beide zu denselben Werten ausgewertet werden):
[
A1 = 4,
A2 = 2,
A3 = 1
]
Datensätze können in anderen Datensätzen enthalten sein bzw. geschachtelt werden. Sie können den Suchoperator ([]
) verwenden, um über den Namen auf die Felder eines Datensatzes zuzugreifen. Der folgende Datensatz enthält beispielsweise ein Feld namens Sales
, das einen Datensatz enthält, und ein Feld namens Total
, das auf die Felder FirstHalf
und SecondHalf
des Datensatzes Sales
zugreift:
[
Sales = [ FirstHalf = 1000, SecondHalf = 1100 ],
Total = Sales[FirstHalf] + Sales[SecondHalf]
]
Der obige Ausdruck ergibt Folgendes nach der Auswertung:
[
Sales = [ FirstHalf = 1000, SecondHalf = 1100 ],
Total = 2100
]
Datensätze können auch in Listen enthalten sein. Mit dem Positionsindexoperator ({}
) können Sie über den numerischen Index auf ein Element in einer Liste zugreifen. Auf die Werte in einer Liste wird mit einem nullbasierten Index am Anfang der Liste verwiesen. Über die Indizes 0
und 1
können Sie beispielsweise auf das erste und zweite Element in der folgenden Liste verweisen:
[
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
]
Listen- und Datensatzelement-Ausdrücke (sowie let-Ausdrücke) werden mithilfe der Lazy Evaluation ausgewertet. Bei diesem Vorgang werden Ausdrücke nur bei Bedarf berechnet. Bei allen anderen Ausdrücken wird die sofortige Auswertung angewendet. Sie werden direkt ausgewertet, wenn sie bei einem Auswertungsprozess auftreten. Sie können sich den Vorgang wie folgt vorstellen: Durch das Auswerten eines Listen- oder Datensatzausdrucks wird ein Listen- oder Datensatzwert zurückgegeben, dem bekannt ist, wie seine Listenelemente oder Datensatzfelder berechnet werden müssen, wenn dies (durch Such- oder Indexoperatoren) angefordert wird.
Functions
In M handelt es sich bei einer Funktion um eine Zuordnung mehrerer Eingabewerte zu einem einzelnen Ausgabewert. In einer Funktion werden zunächst die erforderlichen Eingabewerte (Funktionsparameter) genannt, und nach dem Pfeilsymbol (=>
) wird ein Ausdruck bereitgestellt (Funktionstext), der das Ergebnis der Funktion mithilfe dieser Eingabewerte berechnet. Beispiel:
(x) => x + 1 // function that adds one to a value
(x, y) => x + y // function that adds two values
So wie bei Zahlen und Textwerten handelt es sich auch bei Funktion um Werte. Im folgenden Beispiel wird eine Funktion angezeigt, die den Wert des Add-Felds darstellt. Die Funktion wird von mehreren anderen Feldern aufgerufen oder ausgeführt. Beim Aufrufen einer Funktion werden mehrere Werte angegeben, die logisch durch die erforderlichen Eingabewerte innerhalb des Funktionstextausdrucks ersetzt werden.
[
Add = (x, y) => x + y,
OnePlusOne = Add(1, 1), // 2
OnePlusTwo = Add(1, 2) // 3
]
Bibliothek
In der Standardbibliothek von M, kurz Bibliothek, sind die gängigen Definitionen für die Verwendung verfügbar. Diese Definitionen bestehen aus einer Reihe benannter Werte. Die Namen der von einer Bibliothek bereitgestellten Werte können in Ausdrücken verwendet werden, ohne dass sie explizit in dem Ausdruck definiert werden müssen. Beispiel:
Number.E // Euler's number e (2.7182...)
Text.PositionOf("Hello", "ll") // 2
Operatoren
M enthält Operatoren, die in Ausdrücken verwendet werden können. Operatoren werden auf Operanden angewendet, um symbolische Ausdrücke zu bilden. So sind beispielsweise in dem Ausdruck 1 + 2
die Zahlen 1
und 2
Operanden, und der Operator ist der Additionsoperator (+
).
Die Bedeutung eines Operators kann je nach Wertetyp der Operanden variieren. Der Plusoperator kann z. B. auch mit anderen Wertetypen als Zahlen verwendet werden:
1 + 2 // numeric addition: 3
#time(12,23,0) + #duration(0,0,2,0)
// time arithmetic: #time(12,25,0)
Auch die Bedeutung des Kombinationsoperators (&
) ist operandenabhängig:
"A" & "BC" // text concatenation: "ABC"
{1} & {2, 3} // list concatenation: {1, 2, 3}
[ a = 1 ] & [ b = 2 ] // record merge: [ a = 1, b = 2 ]
Beachten Sie, dass einige Operatoren nicht alle Kombinationen von Werten unterstützen. Beispiel:
1 + "2" // error: adding number and text isn't supported
Ausdrücke, die, wenn sie ausgewertet sind, nicht definierte Operatorbedingungen erkennen, die zu Fehlern ausgewertet werden.
Metadaten
Metadaten sind Informationen zu einem Wert, die einem Wert zugeordnet sind. Metadaten werden als Datensatzwert dargestellt, auch Metadaten-Datensatz genannt. Die Felder eines Metadatensatzes können verwendet werden, um die Metadaten für einen Wert zu speichern.
Jeder Wert verfügt über einen Metadatensatz. Wenn der Wert des Metadatensatzes nicht angegeben wurde, dann ist der Metadatensatz leer (umfasst keine Felder).
Metadaten-Datensätze sind eine einfach Möglichkeit, zusätzliche Informationen mit einer beliebigen Art von Wert zu verknüpfen. Durch das Zuordnen eines Metadatensatzes zu einem Wert wird weder der Wert noch sein Verhalten geändert.
Der Wert eines Metadaten-Datensatzes y
wird über die Syntax x meta y
mit dem vorhandenen Wert x
verknüpft. Der folgende Code ordnet beispielsweise einen Metadatensatz den Feldern Rating
und Tags
mit dem Textwert "Mozart"
zu:
"Mozart" meta [ Rating = 5, Tags = {"Classical"} ]
Wenn Werten, denen bereits ein nicht leerer Metadaten-Datensatz zugeordnet ist, weitere Metadaten zugewiesen werden, werden der neue und der bestehende Metadaten-Datensatz zusammengeführt. Die folgenden beiden Ausdrücke entsprechen sich beispielsweise gegenseitig sowie dem vorherigen Ausdruck:
("Mozart" meta [ Rating = 5 ]) meta [ Tags = {"Classical"} ]
"Mozart" meta ([ Rating = 5 ] & [ Tags = {"Classical"} ])
Auf den Metadaten-Datensatz eines bestimmten Werts kann mithilfe der Funktion Value.Metadata zugegriffen werden. Im folgenden Beispiel greift der Ausdruck im Feld ComposerRating
auf den Metadaten-Datensatz des Werts im Feld Composer
und dann auf das Feld Rating
des Metadaten-Datensatzes zu.
[
Composer = "Mozart" meta [ Rating = 5, Tags = {"Classical"} ],
ComposerRating = Value.Metadata(Composer)[Rating] // 5
]
Let-Ausdruck
In vielen der bisher angeführten Beispiele waren alle literalen Werte des Ausdrucks auch im Ergebnis enthalten. In let
-Ausdrücken können Werte berechnet, benannt und dann in einem nachfolgenden Ausdruck verwendet werden, der auf in
folgt. Im Beispiel mit den Vertriebsdaten können Sie z. B. wie folgt vorgehen:
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
Das Ergebnis des obigen Ausdrucks ist ein Zahlenwert (4600
), der aus den Werten berechnet wird, die an die Namen Sales2007
und Sales2008
gebunden sind.
if-Ausdruck
In einem if
-Ausdruck wird basierend auf einer logischen Bedingung zwischen zwei Ausdrücken ausgewählt. Beispiel:
if 2 > 1 then
2 + 2
else
1 + 1
Der erste Ausdruck (2 + 2
) wird ausgewählt, wenn der logische Ausdruck (2 > 1
) TRUE ist, und der zweite Ausdruck (1 + 1
) wird ausgewählt, wenn er FALSE ist. Der ausgewählte Ausdruck (in diesem Fall 2 + 2
) wird ausgewertet und zum Ergebnis des if
-Ausdrucks (4
).
Errors
Ein Fehler ist ein Hinweis darauf, dass bei der Auswertung eines Ausdrucks kein Wert erzeugt werden konnte.
Fehler werden von Operatoren und Funktionen ausgelöst, die auf error-Bedingungen stoßen, oder durch die Verwendung des Ausdrucks error. Fehler werden mithilfe des try
-Ausdrucks behandelt. Bei Auftreten eines Fehlers wird ein Wert angegeben, mit dem auf die Fehlerursache hingewiesen werden kann.
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])
Im obigen Beispiel wird auf das Feld Sales[UnitPrice]
zugegriffen und eine Wertformatierung durchgeführt, sodass folgendes Ergebnis erzeugt wird:
"Unit Price: 2"
Wenn das Feld Units
den Wert 0 (Null) enthält, löst das Feld UnitPrice
einen Fehler aus, der durch try
behandelt wird. Dies führt zum folgenden Ergebniswert:
"No Units"
Ein try
-Ausdruck wandelt echte Werte und Fehler in einen Datensatzwert um, der angibt, ob der try
-Ausdruck einen Fehler behandelt hat oder nicht. Außerdem wird entweder auf den richtigen Wert oder den Fehlerdatensatz verwiesen, der bei der Fehlerbehandlung extrahiert wurde. Betrachten Sie beispielsweise den folgenden Ausdruck, der einen Fehler auslöst und diesen dann sofort behandelt:
try error "negative unit count"
Dieser Ausdruck wertet den folgenden geschachtelten Datensatzwert aus und erläutert die Suche für die Felder [HasError]
, [Error]
und [Message]
im vorherigen Stückpreisbeispiel.
[
HasError = true,
Error =
[
Reason = "Expression.Error",
Message = "negative unit count",
Detail = null
]
]
Ein gängiges Vorgehen ist es, Fehler durch Standardwerte zu ersetzen. Der try
-Ausdruck kann mit einer optionalen otherwise
-Klausel verwendet werden, um dasselbe Ergebnis mit einem kompakteren Ausdruck zu erreichen:
try error "negative unit count" otherwise 42
// 42