Blog Article & Copyright by Lukas Hillesheim
In Teil 1 dieser Serie wurde darauf hingewiesen, dass die MSDN keine Auskunft über den konkreten (Daten-) Verkehr zwischen der aufrufenden Funktion - meist ein Iterator - und der Lambda Expression gibt. Teil 2 dieser Serie zeigt an drei konkreten Beispielen, wie Power Query Iterator und Lambda Expression miteinander interagieren.
Bezüglich der Interaktion von Iterator und Lambda Expression tauchen folgende Fragen auf:
- - Wie viele Variablen muss die Lambda Expression zur Verfügung stellen, um die Daten des Iterators entgegen zu nehmen (0, 1, n)
- - Welche Daten-Typen werden vom Iterator an die Lambda Expression übergeben?
- - Welcher Daten-Typ (Scalar, Array, Object etc.) muss von der Lambda Expression an den Iterator zurückgegeben werden?
- - Was macht der Iterator mit dem Rückgabe-Wert der Lambda Expression (Business Logik des Iterators)?
- - Welche Daten gibt der Iterator zurück?
Aufruf einer Lambda Expression innerhalb eines Iterators:
<iterator> ( ( <variable>, n ) => <lambda_expression> )
Für die Beispiele dieses Artikels werden diese drei Iteratoren verwendet:
- - List.Transform
- - Table.TransformRows
- - Record.TransformFields
1. Allgemeines
MSDN Hilfe zu den drei Beispiel-Funktionen:
- List.Transform (
- list as list,
- transform as function) as list
- Table.TransformRows(
- table as table,
- transform as function) as list
- Record.TransformFields(
- record as record,
- transformOperations as list) as record
Alle drei Iteratoren implementieren eine Art von ETL-Logik. "ETL" steht für
- - E(xtract). Extraktion der Daten aus der Quelle
- - T(ransform). Anwenden von Logik zur Modifikation der Daten. Ableiten von neuen Daten auf Grund der Quell-Daten
- - L(oad). Ablegen der Daten in das Ziel
Die Lambda Expression ist für das "T", also den Transformations-Teil, verantwortlich.
Iteration. Alle drei Funktionen sind Iteratoren. Aus der OOP-Sicht implementieren sie alle eine Schleife:
- - List.Transform(). Foreach ( item i in <list> ) { … }
- - Table.TransformRows(). Foreach ( Row r in <table>.Rows ) { … }
- - Record.TransformFields(). Foreach ( Field f in <record>.Fields) {...}
Ergebnis vom Typ “Iterable”. Alle drei Funktionen liefern ein Listen-Objekt zurück:
- - List.Transform() as list
- - Table.TransformRows() as list
- - Record.TransformFields() as record. Eine Liste von Feldern
Argument vom Typ “function”. Alle drei Funktionen verfügen über ein Argument vom Typ "function":
- - List.Transform ( … , transform as function ). Einzelne Funktion bzw. Lambda Expression, die eine Transformations-Aufgabe ausführt.
- - Table.TransformRows ( … , transform as function ). Einzelne Funktion bzw. Lambda Expression, die eine Transformations-Aufgabe ausführt.
- - Record.TransformFields ( …, transformOperations as list, … ). Mehrere Funktionen bzw. Lambda Expressions, die pro Feld eine Transformations-Aufgabe durchführen.
2. List.Transform
Beispiel 1 zu List.Transform.
Schritt 1 - Deklaration der Variablen "list0". Eine Liste von drei Nummern wird deklariert.
Schritt 2 - Deklaration der Variablen "list1". Auf der linken Seite: Jede Nummer der Liste wird sukzessive der Lambda Variablen zugewiesen. Auf der rechten Seite: die Lambda Expression multipliziert die Nummer mit 10. Das Ergebnis wird in das Result Set eingefügt.
Beispiel 2 zu List.Transform.
Die Eingabe ist eine Liste mit Nummern, die Schleife läuft drei Mal. In jedem Schleifen-Durchgang wird der konstante Wert "test" in das Result Set eingefügt.
Beispiel 3 zu List.Transform.
Die Eingabe besteht aus einer Liste von Nummern, das Ergebnis ist eine Liste von Records. Abbildung 7 zeigt Record 1
Beispiel 4 zu List.Transform.
Die Eingabe ist eine Liste von Records. Unter Berücksichtigung dieser Tatsache wird die Lambda Variable "record" genannt. Die Lambda Expression auf der rechten Seite gibt ebenfalls einen Wert vom Typ Record zurück. Beide Ausgabespalten, "Id" und "Name", leiten ihren Wert vom Eingabe-Record ab.
Beispiel 5 zu List.Transform.
Die Eingabe besteht aus einer Liste von Listen. Unter Berücksichtigung dieser Tatsache ist der Name "list" für die Lambda Variable vergeben. Die Lambda Expression auf der rechten Seite berechnet die Anzahl der Elemente für jede Liste. Das erste Element ist eine Liste mit Nummern zwischen 1 und 3, das zweite Element ist eine Liste mit Buchstaben von "A" bis "G" und das dritte Element ist eine Liste mit Datums-Werten zwischen 1.7.2022 bis 10.7.2022.
Figure 12 - List.Transform: the output is a list of scalar values each representing the count of list items.
3. Table.TransformRows
Beispiel 1 zu Table.TransformRows
Die Eingabe, "table0", ist eine Tabelle mit drei Zeilen.
Achtung: In PowerQuery muss man zwischen "Zeile" und "Record" unterscheiden. Eine "Zeile" ist ein Element einer Tabelle. Ein "Record" ist ein von einer Tabelle unabhängiges Objekt. Es kann, muss aber nicht unbedingt auch Teil einer Liste sein. Der Unterschied zwischen den ähnlichen Objekten, "Zeile" und "Record", kommt zum Tragen, indem von allen Zeilen einer Tabelle verlangt wird, dass sie über das gleiche Schema verfügen; also gleiche Anzahl von Spalten und gleiche Typen. Von einer Record-Liste wird das nicht erwartet; jeder Record kann einem anderen Schema folgen.
Schritt 1 - Deklaration der Variablen "table0". Inhalt der Variablen:
Schritt 2 - Deklaration der Variablen "list0". Für jede Zeile der Eingabe wird ein neuer Record in die Ausgabe eingefügt. Das Ergebnis ist also eine Liste von Records:
Inhalt des ersten Records:
Schritt 3 - Deklaration der Variablen "table1". Eine Herausforderung bei der Verwendung von "Table.TransformRows" besteht darin, die Liste der Records in eine Tabelle zurück zu verwandeln. Diese Aufgabe wird mit "Table.FromRecords" gelöst:
4. Record.TransformFields
Beispiel 1 zu Record.TransformFields
Schritt 1 - Deklaration der Variablen "record0". Ein Record mit vier Spalten wird deklariert.
Schritt 2 - Deklaration der Variablen "record1". Das zweite Argument für "Record.TransformFields" ist eine Liste von Lambda Expressions. Jede einzelne Lambda Expression ist dafür zuständig, für eine bestimmte Spalte eine Transformation durchzuführen. Die jeweilige Spalte wird "links" genannt. Im Beispiel sind es die Spalten "Amount" und "Date". Jede Spalte des Eingabe-Records, die nicht in der Liste der Transformationen erwähnt wird, wird in den Ergebnis-Record ohne Änderung übernommen. Dies trifft auf "CustId" und "CustName" zu.
Figure 19 - Record.TransformFields: 2 fields were transformed (Amount := amount gross, Date := due date).
Die Syntax-Hilfe der MSDN enthält ein Beispiel, in dem die Funktion "Record.TransformFields" benutzt wird, um die Typen von Spalten zu modifizieren:
Bezüglich des MSDN-Beispiels kann man sich vorstellen, dass der Ausdruck "Number.FromText" von der Power Query Engine zu folgender Lambda Expression expandiert wird:
(fieldValue) => Number.FromText (fieldValue)