Custom Functions Archive | THE SELF-SERVICE-BI BLOG Wir lieben Microsoft Power BI Mon, 14 Apr 2025 07:34:13 +0000 de hourly 1 https://wordpress.org/?v=6.8 https://ssbi-blog.de/wp-content/uploads/2019/10/Favicon-150x150.png Custom Functions Archive | THE SELF-SERVICE-BI BLOG 32 32 Leserfrage: Erstellung einer Funktion für relative Spaltenvergleiche https://ssbi-blog.de/blog/business-topics/leserfrage-erstellung-einer-funktion-fuer-relative-spaltenvergleiche/ https://ssbi-blog.de/blog/business-topics/leserfrage-erstellung-einer-funktion-fuer-relative-spaltenvergleiche/#comments Thu, 27 Jun 2019 08:28:16 +0000 https://ssbi-blog.de/?p=5556 Mich hat vor kurzem eine Leserfrage erreicht, die inhaltlich wie folgt lautete: Wie erstellt man eine Funktion in M, die innerhalb einer Tabelle an einer variablen Position eine Spalte erzeugt, welche die beiden Spalten links davon auf Identität prüft? Ich fand diese Frage recht interessant und denke, dass dies ein gutes Beispiel ist, um das […]

Der Beitrag Leserfrage: Erstellung einer Funktion für relative Spaltenvergleiche erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
Mich hat vor kurzem eine Leserfrage erreicht, die inhaltlich wie folgt lautete:

Wie erstellt man eine Funktion in M, die innerhalb einer Tabelle an einer variablen Position eine Spalte erzeugt, welche die beiden Spalten links davon auf Identität prüft?

Ich fand diese Frage recht interessant und denke, dass dies ein gutes Beispiel ist, um das Erstellen von custom functions im M zu verdeutlichen.

Als Abonnent meines Newsletters erhältst Du die Beispieldateien zu den Beiträgen dazu. Hier geht’s zum Abonnement des Newsletters!

Du kannst meine Funktion dem folgenden unten befindlichen Fenster entnehmen und von dort aus in Deine Zwischenablage kopieren, um sie anschließend in den Erweiterten Editor (Advanced Editor) in Power Query für Excel oder Power BI Desktop einzufügen.

Falls Du sehen möchtest, wie diese Funktion schrittweise vorgeht, um das finale Ergebnis zu ermitteln, dann

  • kommentiere die Zeilen 1-5, 136-147 aus (Stelle vor jede Zeile //) und entferne das Komma hinter „Output“ in Zeile 130
  • kommentiere 10-24 wieder ein (entferne in Zeile 10 /* und in Zeile 24 */)

Ich hoffe, die Kommentierung innerhalb der Funktion ist ausreichend, um die Funktionsweise zu verstehen.

Falls Du wissen möchtest, wie Du meine M-Funktionen in Deinen Projekten wiederverwenden kannst, schau bitte hier nach.

Bis zum nächsten Mal und denk dran: Sharing is caring. Wenn Dir der Beitrag gefallen hat, dann teile ihn gerne. Falls Du Anmerkungen hast, schreibe gerne einen Kommentar, oder schicke mir eine Mail an lars@ssbi-blog.de

Viele Grüße aus Hamburg,

Lars

Der Beitrag Leserfrage: Erstellung einer Funktion für relative Spaltenvergleiche erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
https://ssbi-blog.de/blog/business-topics/leserfrage-erstellung-einer-funktion-fuer-relative-spaltenvergleiche/feed/ 5
Komplexere benutzerdefinierte Funktionen in Power Query schreiben https://ssbi-blog.de/blog/business-topics/komplexere-benutzerdefinierte-funtionen-in-power-query-schreiben/ Tue, 14 Aug 2018 16:33:12 +0000 https://ssbi-blog.de/?p=4138 Im letzten Beitrag habe ich darüber geschrieben was Funktionen eigentlich sind und wie Du Deine erste einfache benutzerdefinierte Funktion in Power Query/ M schreibst. Im heutigen Beitrag möchte ich Dir zeigen, wie Du auch komplexere benutzerdefinierte Funktionen in Power Query schreiben kannst. Je komplexer die Funktion, desto größer ist die Wahrscheinlichkeit, dass der Code hin […]

Der Beitrag Komplexere benutzerdefinierte Funktionen in Power Query schreiben erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
Im letzten Beitrag habe ich darüber geschrieben was Funktionen eigentlich sind und wie Du Deine erste einfache benutzerdefinierte Funktion in Power Query/ M schreibst. Im heutigen Beitrag möchte ich Dir zeigen, wie Du auch komplexere benutzerdefinierte Funktionen in Power Query schreiben kannst. Je komplexer die Funktion, desto größer ist die Wahrscheinlichkeit, dass der Code hin und wieder angepasst werden muss. Wie das geht, zeige ich Dir in diesem Beitrag 🙂

Als Abonnent meines Newsletters erhältst Du die Beispieldateien zu den Beiträgen dazu. Hier geht’s zum Abonnement des Newsletters!

Das Szenario

Um eine etwas komplexere Funktion zeigen zu können, muss es auch eine Problemstellung geben, die es zu lösen gilt. Stell Dir folgendes Szenario vor. Ich bekomme monatlich eine txt-Datei aus einer anderen Abteilung zugesandt, die ich zu analysieren habe. Leider liegen die Daten nicht in der gewünschten Form vor, die ich für meine Analysen benötige. Daher nehme ich Power Query zu Hilfe und erstelle eine Lösung, die mir die Datenlieferung in eine nützliche, flache Tabelle verwandelt:

Von der unstrukturierten txt-Datei zur flachen tabelle in Excel, Power Query, Power BI Desktop
Von der schlecht strukturierten txt-Datei zur flachen Tabelle in Excel

Diese Tabelle exportiere ich anschließend in eine Exceltabelle für die weiterführende Analyse.

Das Abfrageergebnis in Excel, Power Query, Power BI Desktop
Das Abfrageergebnis in Excel

Der nächste Monat

Mit dem neuen Monat erfolgt eine erneute Datenlieferung, die in ein neues Tabellenblatt in Excel geladen werden soll. Es gibt wie immer mehrere Lösungsmöglichkeiten. Ein valider Ansatz ist eine Funktion, welche den Pfad der zu transformierenden txt-Datei aufnimmt und dann die gewünschte Tabellenstruktur erzeugt, so wie hier:

Datentransformation durch benutzerdefinierte Funktion, Power Query, Power BI Desktop
Datentransformation durch benutzerdefinierte Funktion

Pfad zur Datenquelle eingeben, bestätigen und die Daten liegen in der benötigten Form vor. Sieht das für Dich interessant aus? Schauen wir uns an, wie das geht.

Die Erstellung der benutzerdefinierten Funktion

Um diese benutzerdefinierte Funktion zu erstellen, dupliziere ich die Abfrage Datenlieferung, durch einen Rechtsklick auf die Abfrage → Duplizieren. Der neuen Abfrage gebe ich den Namen fnTableTransform, wobei der Präfix fn für Funktion steht. Jetzt werde ich diese Abfrage in eine Funktion umwandeln. Hierzu gehe ich in den Erweiterten Editor der Abfrage, um Einsicht in den dahinterliegenden M-Code zu erhalten:

So öffnest Du den Erweiterten Editor, Power Query, Power BI Desktop
So öffnest Du den Erweiterten Editor

Werfen wir einen Blick auf den M-Code…

Der Blick in den Erweiterten Editor

Der erste Blick in den Erweiterten Editor dürfte für Dich verwirrend sein.

Der erste Blick auf den M-Code, Power Query, Power BI Desktop
Der erste Blick auf den M-Code

M ist eine funktionale Sprache, dessen Logik sich mir beim ersten Betrachten damals nicht auf Anhieb erschloss. Ich möchte hier daher kurz die notwendigen Dinge erläutern:

  • Der gesamte Code ist in Schritte unterteilt, die alle innerhalb eines Let-in-Statements definiert sind
  • Jeder Schritt hat einen Namen, z. B. Quelle, oder auch #"Geänderter Typ"
  • Schritte bauen zumeist (aber nicht zwangsläufig) aufeinander auf. Daher sieht man es häufig, dass der Name eines Schrittes im darauffolgenden Schritt innerhalb der Funktionen benutzt wird (siehe rote und gelbe Markierung im Screenshot).
  • Derjenige Schritt, der nach dem in benannt ist (letzte Zeile im Skript), stellt das Ergebnis der gesamten Abfrage da. Das Ergebnis dieses Schrittes wird dem Nutzer – zumeist, aber nicht notwendigerweise – als Tabelle zurückgegeben. In meinem Beispiel ist dies der grün markierte Schritt #"Geänderter Typ1".

So viel kurz zum Verständnis des M-Codes. Diesen Code baue ich jetzt zu einer Funktion um.

Den bestehenden Code zu einer Funktion umgestalten

Ich hatte bereits im letzten Beitrag gezeigt, dass eine benutzerdefinierte Funktion in M mit ()=> eingeleitet wird. Zudem hatte ich gezeigt, dass zwischen diesen beiden Klammern die Aufnahme eines (oder mehrerer) Parameter definiert werden kann. Meine Funktion benötigt einen Parameter, der den Pfad der zu transformierenden Datei aufnehmen und an die Funktion weiterreichen kann. Das Ganze funktioniert wie folgt:

So wird der Code von einer Abfrage in eine Funktion konvertiert, Power BI Desktop, Power Query
So wird der Code von einer Abfrage in eine Funktion konvertiert

Durch das Voranstellen von (FileFullPath as text) as table =>  gestalte ich die Abfrage in eine Funktion um, die einen Parameter (FileFullPath) vom Typ text aufnehmen kann. Der Name FileFullPath ist hierbei völlig frei wählbar, sollte aber sprechend für Dich sein. Mit as table definiere ich, dass der Rückgabewert der Funktion vom Typ Tabelle sein muss. Ich möchte ja schließlich die transformierte Tabelle in Excel einfügen und nutzen können. Auf der Nutzeroberfläche äußert sich mein Handeln so:

Die Nutzeroberfläche der erstellten, benutzerdefinierten Funktion, Power Query, Power BI Desktop
Die Nutzeroberfläche der erstellten, benutzerdefinierten Funktion

Das sieht bis hierhin schon mal sehr vielversprechend aus. Ich teste die Funktion an dieser Stelle, indem ich den Dateipfad zur August-Datei einfüge und auf Aufrufen klicke.

Es wird immer noch die Julidatei transformiert, Power Query, Power BI Desktop
Es wird immer noch die Julidatei transformiert

Ich bekomme zwar eine transformierte Tabelle zurückgeliefert, aber wenn Du genau hinsiehst, dann fällt Dir auf, dass die Funktion die Juli-Datei zurückgeliefert hat, obwohl ich den Pfad für die August-Datei übergeben habe. Die Ursache hierfür ist schnell gefunden: Ich habe zwar den Parameter für die Funktion definiert, diesen jedoch noch nicht in den Funktionskörper eingebunden. Hier steht der zu nutzende Pfad zur Datei immer noch als feste Zeichenkette drin:

Der aufgenommene Parameter kommt noch nicht im Funktionskörper an, Power Query, Power BI Desktop
Der aufgenommene Parameter kommt noch nicht im Funktionskörper an

Die Lösung ist recht einfach. Ich muss die Zeichenkette durch den Parameter ersetzen und diesen damit in den Funktionskörper einbinden.

Die Parameter in den Funktionskörper einbinden

Um den Inhalt des Parameters an die Funktion übergeben zu können, muss der fest definierte Pfad innerhalb des Schrittes Quelle durch den Namen des Parameters (bei mir FileFullPath) ersetzt werden.

Der Parameter ist korrekt in den Funktionskörper eingebunden, Power Query, Power BI Desktop
Der Parameter ist nun korrekt in den Funktionskörper eingebunden

Jetzt liefert die Funktion die gewünschte Datei zurück.

Die Funktion liefert die korrekte Datei zurück, Power Query, Power BI Desktop
Die Funktion liefert die korrekte Datei zurück

Wir haben jetzt das gewünschte Ergebnis erzielt. Aber eine Frage stellt sich jetzt noch: Wie kann ich die Funktion bei Bedarf anpassen?

So passt Du Deine Funktion an

Du hast bereits gesehen, dass das Ergebnis einer aufgerufenen Funktion in einer separaten Abfrage zurückgegeben wird und nicht in der Abfrage, die die Funktion definiert. Jetzt möchte ich meine Funktion jedoch leicht verändern und sofort sehen, wie sich die Veränderung auf den Rückgabewert der Funktion auswirkt. Mit der bisherigen Lösung müßte ich nach jeder Anpassung der Funktion in die Abfrage „Aufgerufene Funktion“ gehen um zu sehen, wie sie sich ausgewirkt hat. Somit würde ich ständig zwischen Funktion und Abfrage hin und herspringen. Das ist ziemlich lästig. Ich zeige Dir einen besseren Weg.

Eine Funktion in einer Abfrage umwandeln

Wir haben zu Beginn eine Abfrage in eine Funktion konvertiert… Dies geht natürlich auch andersherum 🙂

Die Rückverwandlung der Funktion in eine Abfrage, Power Query, Power BI Desktop
Die Rückverwandlung der Funktion in eine Abfrage

Indem ich „//“ vor den funktionsdefinierenden Teil setze (1), wandle ich die Funktion zurück in eine gewöhnliche Abfrage. Mit „//“ werden Zeilen innerhalb des M-Codes auskommentiert, d. h. diese Zeilen werden nicht bei der Ausführung der Funktion berücksichtigt. Auf diese Weise kann man auch Code-Zeilen in M kommentieren, was die Lesbarkeit des Codes stark verbessert. Bestätige ich jetzt mit Fertig, erhalte ich jedoch eine Fehlermeldung, weil der Schritt Quelle immer noch nach dem Parameter sucht, den ich aber gerade auskommentiert habe. Um diesen Fehler abzufangen, füge ich zu Beginn einen Schritt mit dem Namen des Parameters ein (2) und weisen diesem den Pfad zur entsprechenden Datei zu. Auf diese Weise kann die Datei korrekt importiert werden. Bestätige ich jetzt mit Fertig, kann ich mir das Ergebnis eines jeden einzelnen Schrittes, wie für Abfragen üblich, ansehen.

Der Vorteil von Abfragen gegenüber Funktionen: Ich sehe die Ergebnisse eines jeden Schrittes sofort, Power Query, Power BI Desktop
Der Vorteil von Abfragen gegenüber Funktionen: Ich sehe die Ergebnisse eines jeden Schrittes sofort

Jetzt möchte ich meine Funktion dahingehend anpassen, dass die erste Spalte ‚Monat und Jahr‘ und zwei Spalten aufgeteilt wird: ‚Jahr‘ und ‚Monat‘.

Die inhaltliche Anpassung der Funktion vornehmen

Um die bestehende Spalte in zwei Spalten aufzuteilen und diese Spalten umzubenennen, kann ich mich Standardfunktionalitäten von Power Query bedienen. Hierzu gehe ich wie folgt vor:

  • Ich markiere die Spalte ‚Monat und Jahr‘
  • Dann klicke ich auf Transformieren → Spalten teilen  → Nach Trennzeichen → Leerzeichen
  • Danach benenne ich die beiden neuen Spalten entsprechend um

Das Ergebnis sieht dann wie folgt aus:

Die angepasste Abfrage mit getrennter Monats- und Jahresspalte, Power Query, Power BI Desktop
Die angepasste Abfrage mit getrennter Monats- und Jahresspalte

Die Anpassung umfasst drei neue Schritte (rot gerahmt) und liefert das gewünschte Ergebnis. Der letzte Schritt, der jetzt noch zu unternehmen ist, ist die Rückverwandlung der Abfrage in eine Funktion.

Die Abfrage in eine Funktion zurückverwandeln

Um aus der Funktion eine Abfrage zu machen, habe ich den funktionsdefinierenden Teil auskommentiert und einen Schritt eingefügt, der den Namen des Parameters trug. Das mache ich jetzt natürlich umgekehrt. Ich entferne die beiden „//“ vor dem Funktionskopf und kommentiere den Schritt FileFullPath mit „//“ aus. Diesen könnte ich auch löschen, aber vielleicht brauche ich den bei der nächsten Anpassung nochmal. 😉 Wie Du sehen kannst (rot gerahmt), hat die Funktion jetzt die drei Schritte mehr, die ich vorhin definiert habe.

Rolle rückwärts: Die angepasste Abfrage erneut in eine Funktion wandeln, Power Query, Power BI Desktop
Rolle rückwärts: Die angepasste Abfrage erneut in eine Funktion wandeln

Rufe ich die Funktion von nun an auf, ist die Spalte ‚Jahr und Monat‘ von vornherein in zwei Spalten aufgeteilt.

Bis zum nächsten Mal und denk dran: Sharing is caring. Wenn Dir der Beitrag gefallen hat, dann teile ihn gerne. Falls Du Anmerkungen hast, schreibe gerne einen Kommentar, oder schicke mir eine Mail an lars@ssbi-blog.de

Viele Grüße aus Hamburg,

Lars

Ich schreibe meine Beiträge für Dich, den Leser. Bitte schenke mir eine Minute Deiner Zeit und bewerte die folgenden Kategorien, um mir zu helfen meine Beiträge so gut wie möglich zu schreiben. Danke 🙂

Der Beitrag Komplexere benutzerdefinierte Funktionen in Power Query schreiben erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
Wie Du benutzerdefinierte Funktionen in Power Query schreibst https://ssbi-blog.de/blog/business-topics/wie-du-benutzerdefinierte-funktionen-in-power-query-schreibst/ https://ssbi-blog.de/blog/business-topics/wie-du-benutzerdefinierte-funktionen-in-power-query-schreibst/#comments Thu, 05 Jul 2018 20:00:22 +0000 https://ssbi-blog.de/?p=4103 Power Query hat eine Vielzahl nativer Funktionen zu bieten, die Dir das Leben erleichtern, doch das ist noch lange nicht alles. Es ist auch möglich eigene, sogenannte benutzerdefinierte Funktionen in Power Query zu schreiben. Damit kannst Du Dir die Arbeit erheblich erleichtern, indem Du wiederholt genutzte Funktionalitäten in Funktionen auslagerst/ kapselst und wiederholt aufrufst. Das […]

Der Beitrag Wie Du benutzerdefinierte Funktionen in Power Query schreibst erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
Power Query hat eine Vielzahl nativer Funktionen zu bieten, die Dir das Leben erleichtern, doch das ist noch lange nicht alles. Es ist auch möglich eigene, sogenannte benutzerdefinierte Funktionen in Power Query zu schreiben. Damit kannst Du Dir die Arbeit erheblich erleichtern, indem Du wiederholt genutzte Funktionalitäten in Funktionen auslagerst/ kapselst und wiederholt aufrufst. Das klingt für Dich interessant? Dann lies weiter, denn ich zeige Dir, wie Du benutzerdefinierte Funktionen in Power Query schreibst.

Als Abonnent meines Newsletters erhältst Du die Beispieldateien zu den Beiträgen dazu. Hier geht’s zum Abonnement des Newsletters!

Was sind überhaupt Funktionen?

Jeder Excel-Anwender kennt Funktionen. Sie nehmen in der Regel eine gewisse Anzahl Parameter auf und geben einen Wert zurück. Die Parameter sind dabei entweder Pflichtparameter (auf diese kann für die Ermittlung des Ergebnisses nicht verzichtet werden), oder optionale Parameter, die für das Ergebnis der Funktion nicht zwingend benötigt werden. In seltenen Fällen nehmen Funktionen auch keinen Parameter auf. Ein Beispiel hierfür wäre die Excel-Funktion HEUTE(), die das aktuelle Tagesdatum zurückliefert. Schauen wir uns Funktionen in Excel an.

Funktionen in Excel

Die zu bildende Summe der Summanden 1 und 2 kann auch ohne Funktion über C2+C3 ermittelt werden:

Summenbildung in Excel, ohne Funktion, Power Query, Power BI Desktop
Summenbildung in Excel, ohne Funktion

 

Das Ganze hört jedoch auf Spaß zu machen, sobald ich mehr als zwei Werte habe:

Summenbildung in Excel, ohne Funktion, bei vielen Summanden, Power Query, Power BI Desktop
Summenbildung in Excel, ohne Funktion, bei vielen Summanden

 

Abhilfe schafft hier die wohl bekannteste Excel-Funktion: Die Funktion SUMME(). Lass uns einen Blick auf die Funktionsweise dieser Funktion werfen:

Summenbildung ist mit Funktion deutlich komfortabler, Power Query, Power BI Desktop
Summenbildung ist mit Funktion deutlich komfortabler

Ich muss der Funktion SUMME() nicht alle Parameter einzeln übergeben, denn diese Funktion akzeptiert als Parameter auch einen Bereich von Zellen (in meinem Beispiel der Bereich C2:C11). Funktionen erleichtern uns also das Leben, indem sie nach Übergabe bestimmter Parameter mehr oder weniger komplexe Rechenoperationen für uns durchführen und das Ergebnis (in diesem Beispiel einen einzelnen Wert) zurückliefern. Schauen wir uns das Ganze in Power Query an.

Funktionen in Power Query

In Power Query erfüllen Funktionen dieselbe Aufgabe, wie in Excel, allerdings haben wir hier bei der Art der zurückgelieferten Ergebnisse mehr Optionen. Die gängisten Optionen sind die folgenden.

Ergebnis: Skalarer Wert

Die Kalkulation eines skalaren Wertes, in meinem Beispiel die zeilenweise Summe der Werte Wert1 und Wert2.

Skalarer Wert: Zeilenweise Summe der Werte 1 und 2, Power Query, Power BI Desktop
Skalarer Wert: Zeilenweise Summe der Werte 1 und 2

Ergebnis: List

Die Kalkulation einer Liste von Werten, in meinem Beispiel eine Liste der Werte von Wert1 bis Wert2.

List: Zeilenweise Kalkulation einer Liste, Power Query, Power BI Desktop
List: Zeilenweise Kalkulation einer Liste

Ergebnis: Table

Die Kalkulation einer Tabelle, in meinem Beispiel eine Tabelle mit der Spalte Column1 und den Werten von Wert1 bis Wert2.

Table: Zeilenweise Kalkulation einer Tabelle, Power Query, Power BI Desktop
Table: Zeilenweise Kalkulation einer Tabelle

Ergebnis: Record

Die Kalkulation eines Records, in meinem Beispiel ein Record mit den Felder Feld1 und Feld2 und den Werten aus Spalte Wert1 und Wert2.

Record: Zeilenweise Kalkulation eines Records, Power Query, Power BI Desktop
Record: Zeilenweise Kalkulation eines Records

Skalare Werte, Listen, Tabellen und Records werden für die unterschiedlichsten weiterführenden Berechnungen benötigt, auf die ich hier nicht weiter eingehen werde. Wichtig sind an dieser Stelle lediglich zwei Erkentnisse:

  • Funktionen erfüllen in Power Query die gleiche Aufgabe wie es Funktionen in Excel tun: Sie nehmen Parameter auf, führen auf dessen Basis Berechnungen aus und geben anschließend Werte zurück.
  • Rückgabewerte in Power Query können andere Formen haben, als es in Excel der Fall ist.

Dies sind nicht die einzigen Möglichkeiten für Rückgabewerte einer Funktion, aber es sind die geläufigsten.

Wann es sinnhaft ist, eine Benutzerdefinierte Funktionen zu schreiben

Zum gegenwärtigen Zeitpunkt existieren in Power Query knapp 680 Funktionen. Doch was ist, wenn Du andere Funktionalitäten benötigst, die die nativen Funktionen so nicht zur Verfügung stellen? Am besten erklärt sich so etwas an einem Beispiel.

Ein Beispiel: Die Berechnung einer Quersumme

Eine Quersumme ist die Summe der Ziffern einer mehrstelligen Zahl. Die Quersumme von 123 ist also 1+2+3=6. Es gibt in Power Query keine einzelne Funktion, die die Quersumme von Werten kalkuliert. Möchte ich eine Quersumme in Power Query kalkulieren, so muss ich verschiedene Funktionen verschachtelt nutzen. Eine mögliche Lösung sieht wie folgt aus:

Kalkulation einer Quersumme über verschachtelte native M-Funktionen, Power Query, Power BI Desktop
Kalkulation einer Quersumme über verschachtelte native M-Funktionen

Die Funktionsweise dieser Lösung ist nicht Gegenstand der Diskussion, aber ich denke Du bist mit mir darüber einig, dass es ermüdend wäre, immer wieder dieselbe Formel schreiben, oder kopieren zu müssen, falls ich an anderer Stelle erneut die Berechnung einer Quersumme benötigen würde. Jetzt sieh Dir mal die Berechnung der nächsten Quersummen-Spalte an:

Kalkulation einer Quersumme über eine benutzerdefinierte Funktion, Power Query, Power BI Desktop
Kalkulation einer Quersumme über eine benutzerdefinierte Funktion

Das Ergebnis dieser berechneten Spalte ist deckungsgleich mit der vorherigen, aber die Formel zur Erstellung ist deutlich übersichtlicher, oder?! 😉 Der Grund hierfür ist, dass ich eine benutzerdefinierte Funktion geschrieben habe, die den Namen fnQuersumme trägt. Diese Funktion führt exakt denselben Code aus, wie im ersten Beispiel, jedoch ist dieser Code in eben dieser Funktion gekapselt und kann beliebig oft durch Aufrufen des Funktionsnamens und Übergabe der Spalte Zahl als Parameter wiederverwendet werden: Egal wo ich innerhalb dieser Power Query-Instanz die Bildung einer Quersumme benötige – ich kann mit fnQuersumme(Zahl zur Quersummenbildung) die Quersumme einer Zahl bilden. Die Vorteile einer solchen Funktion sind also:

  • Wiederverwendbarkeit gekapselter Funktionalitäten (durch Aufruf des Funktionsnamens)
  • Deutlich kürzerer und damit übersichtlicherer Code (Aufruf des Funktionsnamens statt des gesamten Funktionskörpers)

Immer dann, wenn mir auffällt, dass ich bestimmte Codebestandteile aus anderen Abfragen kopiere und mehrfach in bestimmte Abfragen einfüge, beginne ich über die Entwicklung einer entsprechenden Funktion nachzudenken. Doch wie erstellt man die eigentlich?

So schreibst Du eine benutzerdefinierte Funktion

Im Gegensatz zu DAX ist es in Power Query/ M möglich, eigene Funktionen zu schreiben. Die Funktionen können dabei sehr vielfältige Komplexitätsgrade aufweisen. Ich beginne aus didaktischen Gründen mit einer sehr einfache Funktion, ohne jegliche Parameter.

Eine einfache Funktion, ohne Parameter

Hierzu öffne ich in Power Query eine leere Abfrage, indem ich einen Rechtsklick mit der Maus in den Bereich der Abfragen mache und Leere Abfrage auswähle:

Das Einfügen einer leeren Abfrage in Power Query, Power BI Desktop
Das Einfügen einer leeren Abfrage in Power Query

Zu allererst gebe ich der Abfrage, die ich zur Funktion umbauen werde, einen Namen (1): fnEinfacheFunktion(). Anschließend öffne ich den Erweiterten Editor (2).

Ein Blick auf den M-Code: Über den Erweiterten Editor, Power Query, Power BI Desktop
Ein Blick auf den M-Code: Über den Erweiterten Editor

Der Erweiterte Editor zeigt auch bei leeren Abfragen standardmäßig ein leeres Let-Statement. Dieses benötige ich für meine einfache Funktion nicht und überschreibe es daher einfach wie folgt:

Den Standard-Code durch die benutzerdefinierte Funktion überschreiben, Power Query, Power BI Desktop
Den Standard-Code durch die benutzerdefinierte Funktion überschreiben

Wundere Dich nicht, über die Schreibweise. In Power Query werden benutzerdefinierte Funktionen mit ()=> eingeleitet. Die Aufgabe dieser einfachen Funktion ist es, bei jedem Aufruf die Zeichenkette „Ich bin eine einfache Funktion, ohne Parameter“ zurückzugeben. Bestätige ich die Abfrage nun mit Fertig, dann sieht das Ergebnis wie folgt aus:

Die fertige benutzerdefinierte Funktion aufrufen, Power Query, Power BI Desktop
Die fertige benutzerdefinierte Funktion aufrufen

Die Abfrage hat nun ein fx als Präfix erhalten, was sie unter den Abfragen optisch als Funktion kennzeichnet. Zudem gibt es jetzt die Schaltfläche Aufrufen, die meine Funktion ausführt und dessen Ergebnis in einer neuen Abfrage ausgibt. Das Ergebnis des Funktionsaufrufes sieht, wenig überraschend, so aus:

Das Ergebnis des Funktionsaufrufes, Power Query, Power BI Desktop
Das Ergebnis des Funktionsaufrufes

Funktionen ohne Parameter sind eher selten, werden aber beispielsweise genutzt, um das aktuelle Tagesdatum widerzugeben. Deutlich praxisrelevanter wird dies, wenn übergebene Parameter innerhalb der Funktion verarbeitet werden.

Eine einfache Funktion, mit Parameter

Ich nehme die vorherige Abfrage als Basis, lege mir von dieser Abfrage eine Kopie an und nenne diese fnEinfacheFunktionMitParameter(). Im Erweiterten Editor passe ich die Funktion wie folgt an:

Die benutzerdefinierte Funktion mit Funktionsparameter, Power Query, Power BI Desktop
Die benutzerdefinierte Funktion mit Funktionsparameter

Im Vergleich zur vorherigen Funktion habe ich zwei Änderungen vorgenommen:

  1. Zwischen der öffnenden und schließenden Klammer habe ich den Parameter Parameteranzahl eingefügt und ihm den Datentyp number zugewiesen. Damit ist die Funktion in der Lage diesen Parameter aufzunehmen und weiterzuverwenden.
  2. Ich habe diesen Parameter in den Funktionskörper integriert. Da Power Query Texte und Zahlen nicht miteinander kombinieren kann, habe ich die Parameteranzahl durch Number.ToText(Parameteranzahl) in einen Text konvertiert, bevor ich diesen mit der gesamten Meldung (über &-Zeichen, wie in Excel) verknüpfe.

Über die Nutzeroberfläche kann ich der Funktion die Parameteranzahl übergeben (in meinem Beispiel 5) und kann sehen, wie der Parameter in den Rückgabewert integriert wird:

Aufruf der benutzerdefinierten Funktion, inklusive Parametereingabe, Power Query, Power BI Desktop
Aufruf der benutzerdefinierten Funktion, inklusive Parametereingabe

Damit habe ich die Funktionsweise von benutzerdefinierten Funktionen erläutert. Allerdings entfalten diese Funktionen zumeist erst dann ihr volles Potential, wenn sie innerhalb anderer Abfragen eingesetzt werden. Was ich damit meine, zeige ich Dir nun.

Funktionen in anderen Abfragen aufrufen

Bisher habe ich die geschriebenen Funktionen nur über die Nutzeroberfläche aufgerufen. Einen viel praktischeren Nutzen bekommt eine benutzerdefinierte Funktion jedoch, wenn man sie in anderen Abfragen nutzt. Ausgangspunkt ist eine Abfrage, die eine Spalte AnzParam beinhaltet, deren Werte nummerisch sind und von 1 bis 10 gehen. Ich kann nun (wie vorhin schon beim Beispiel mit der Quersumme gezeigt), eine neue benutzerdefinierte Spalte hinzufügen, in welcher meine gerade erstellte benutzerdefinierte Funktion aufgerufen wird. Ich übergebe ihr die Werte aus Spalte AnzParam als Parameter. Dieser Funktionsaufruf findet in der Tabelle automatisch zeilenweise statt, so dass in jeder Zeile ein anderer Wert (1, 2… 10) an die Funktion übergeben wird. Der Rückgabewert ist somit je Zeile verschieden.

Aufruf der benutzerdefinierten Funktion in einer berechneten Spalte, Power Query, Power BI Desktop
Aufruf der benutzerdefinierten Funktion in einer berechneten Spalte

Benutzerdefinierte Funktionen sind Bestandteil vieler Programmiersprachen. Vielleicht kennst Du das Prinzip auch schon aus VBA. Falls benutzerdefinierte Funktionen für Dich ein vollkommen neues Konzept sind, wirst Du wahrscheinlich einen Moment brauchen, um es zu verdauen. Das ist vollkommen normal. Ich kann Dir nur empfehlen, Dich mit diesem Thema zu beschäftigen und Dir über die Zeit Deine eigene Funktionsbibliothek anzulegen.

Anlegen einer Funktionsbibliothek, Power Query, Power BI Desktop
Anlegen einer Funktionsbibliothek

Diese Funktionen speichere ich dann in einer leeren Exceldatei (oder auch Power BI Desktop-Datei) und nutze dies stets als Startpunkt für neue Projekte. Das spart Zeit, minimiert Fehler und ist professionell 😉

Fazit

Hier nochmal das Wichtigste auf einen Blick:

  • Funktionen kapseln Funktionalitäten und machen diese so leicht wiederverwendbar
  • Ihr Aufruf verhindert, dass Code immer und immer wieder neu geschrieben/ kopiert werden muss und macht die Abfrage übersichtlicher
  • Funktionen werden durch ()=> eingeleitet
  • Sie können Parameter aufnehmen, diese im Funktionskörper verarbeiten und damit den Rückgabewert beeinflussen
  • Häufig verwendete Funktionen sollten in eine Funktionsbibliothek münden, die dann Startpunkt neuer Projekte ist

In meinem nächsten Beitrag werde ich zeigen, wie Du komplexere benutzerdefinierte Funktionen schreiben kannst.

Bis zum nächsten Mal und denk dran: Sharing is caring. Wenn Dir der Beitrag gefallen hat, dann teile ihn gerne. Falls Du Anmerkungen hast, schreibe gerne einen Kommentar, oder schicke mir eine Mail an lars@ssbi-blog.de

Viele Grüße aus Hamburg,

Lars

Ich schreibe meine Beiträge für Dich, den Leser. Bitte schenke mir eine Minute Deiner Zeit und bewerte die folgenden Kategorien, um mir zu helfen meine Beiträge so gut wie möglich zu schreiben. Danke 🙂

Der Beitrag Wie Du benutzerdefinierte Funktionen in Power Query schreibst erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
https://ssbi-blog.de/blog/business-topics/wie-du-benutzerdefinierte-funktionen-in-power-query-schreibst/feed/ 2
Custom M function: GetTableOfDateAndDateTime https://ssbi-blog.de/blog/technical-topics-english/custom-m-function-gettableofdateanddatetime/ https://ssbi-blog.de/blog/technical-topics-english/custom-m-function-gettableofdateanddatetime/#comments Tue, 03 Apr 2018 11:50:29 +0000 http://ssbi-blog.de/?p=3422 I am a huge fan of Power Query and the M language, but honestly I find it a bit inconvenient to create lists of date values or datetime values, using the standard M functions List.Dates() and List.DateTimes(), mainly because I cannot define an end date/ datetime value for my list, but have to specify the count […]

Der Beitrag Custom M function: GetTableOfDateAndDateTime erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
I am a huge fan of Power Query and the M language, but honestly I find it a bit inconvenient to create lists of date values or datetime values, using the standard M functions List.Dates() and List.DateTimes(), mainly because I cannot define an end date/ datetime value for my list, but have to specify the count parameter. For that reason I created my own custom function GetTableOfDateAndDateTime(), which I want to share and explain with this post.

You can copy all code samples from down below. If you already have my Power Query editor for Notepad++ (or want to build it) you can paste the code in Notepad++. Otherwise just copy it and paste it into the Advanced Editor of Power Query in Excel or Power BI Desktop. 

Update, 7th of June 2018

Due to the feedback from Uwe Mester and Maxim Zelensky, I extended my function so that you can decide if a table with datetime values should be split into two columns (one for date, the other for time). This is done on the basis of the „SplitDateAndTime“ parameter:

Choosing to split Date and time, or not, Power Query, Custom function
Choosing to split Date and time, or not

Here comes an example:

Split date and time, Power Query
Split date and time

All other points below remain.

Purpose of the function

The purpose of this function is to easily create tables for date and datetime values with any increment, based on a start date/datetime and an end date/datetime.

Functionality of the function

Here you learn everything about accepted parameters and the rules how to use them in the function.

Accepted parameters

  1. Start of type date or datetime, e.g. 2018/1/1 or 2018/1/1 01:05:13 → important is to observe the following structure: YYYY/MM/DD or YYYY/MM/DD hh:mm:ss
  2. End of type date or datetime, e.g. 2018/1/1 or 2018/1/1 01:05:13 → important is to observe the following structure: YYYY/MM/DD or YYYY/MM/DD hh:mm:ss
  3. Step of type number, e.g. 1, 12, 27
  4. Unit of type text, which has the allowed values Day, Hour, Minute and Second

Rules

  1. Start and End must be of the same type. They must be either of type date or both of type datetime.
  2. Start must be before End.
  3. Step must be a positiv number

Examples

Get a table of dates, starting from the 1st of January until the 10th of January, growing day-wise with an increment of 1:

Start and End as type date, step 1, growing by Days, Power Query
Start and End as type date, step 1, growing by Days

Get a table of dates, starting from the 1st of January until the 10th of January, growing day-wise with an increment of 3:

Start and End as type date, step 3, growing by Days, Power Query
Start and End as type date, step 3, growing by Days

Even if your entries for Start and End are of type date, you can let your table grow with the units Hour, Minute and Second. In this case, the calculation starts at 0 o’clock on the start day and continues until the end day at 0 o’clock. The following example shows how to grow your table by hour, starting at 1st of January 2018 and ending at the 2nd.

Start and End as type date, step 1, growing by Hour, Power Query
Start and End as type date, step 1, growing by Hour

If you want to define start and end times more granularly, you can do this by entering Start and End as datetimes. The following example starts the table at the 1st of January 2018, 01:05:13 and ends at the same day, 10:00:00. The table grows in 20-minute steps:

Start and End as type datetime, step 20, growing by Minute, Power Query
Start and End as type datetime, step 20, growing by Minute

The function body

You can use the following M code as you like. Just copy it into the Advanced Editor in Power Query and give it a meaningful name, e. g. GetTableOfDateAndDateTime.

https://gist.github.com/SchreiberLars/7e2f2d9a31f4e613daf2fa620e384f9b

I am looking forward to your feedback and suggestions for improvement.

Regards from Germany,

Lars

I write my posts for you, the reader. Please take a minute to help me write my posts as well as possible. Thank you 🙂

[yasr_visitor_multiset setid=2]

Der Beitrag Custom M function: GetTableOfDateAndDateTime erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
https://ssbi-blog.de/blog/technical-topics-english/custom-m-function-gettableofdateanddatetime/feed/ 2
Writing documentation for custom M-functions, Part3 https://ssbi-blog.de/blog/technical-topics-english/writing-documentation-for-custom-m-functions-part3/ https://ssbi-blog.de/blog/technical-topics-english/writing-documentation-for-custom-m-functions-part3/#comments Mon, 12 Mar 2018 09:26:35 +0000 http://ssbi-blog.de/?p=2996 In my two previous posts you could see how to add documentation to custom M functions in Power Query for Excel and Power BI Desktop. In the current post I describe how such documentation can be added to the individual parameters of a function. I will also discuss how to make allowed values of a […]

Der Beitrag Writing documentation for custom M-functions, Part3 erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
In my two previous posts you could see how to add documentation to custom M functions in Power Query for Excel and Power BI Desktop. In the current post I describe how such documentation can be added to the individual parameters of a function. I will also discuss how to make allowed values of a parameter selectable by dropdowns. Have fun.

You can download all code samples from here. If you already have my Power Query editor for Notepad++ (or want to build it) you can open the file in Notepad++. Otherwise open it in a simple text editor and paste it into the Advanced Editor of Power Query or Power BI Desktop. I will refer more frequently to the Microsoft Power Query for Excel Formula Language Specification. You can download it here.

Extend the functionality – sort the list in ascending or descending order

Now I would like to extend the funtionality of my custom function in that way, that the user can choose, wether the returned list of dates will be sorted in an ascending or descending order. Therefore I do the following steps:

  • I add the optional parameter SO (short for sort order).
  • I also change the functions‘ code, so that the list will be sorted in ascending order, if SO is null, or „ascending“. If it is something different, the sort order will be descending.
  • I add SO also to the definition of my custom type fnType

All these changes are highligted in red in the following screenshot:

Adding an optional parameter SO for choosing the sort order of dates, Power Query, Power BI Desktop
Adding an optional parameter „SO“ for choosing the sort order of dates

The result is the following:

The optional parameter "SO" in action, Power Query, Power BI Desktop
The optional parameter „SO“ in action

With this additional parameter I am now able to sort the date list in ascending or descending order by typing the words „descending“ or „ascending“ into the text box. A much better user experience would of course be if this were not a free field, but sorting could be selected via a dropdown. Let’s do this in the next step.

Limiting parameters to Allowed Values

Passing values of parameters as free text can often lead to errors. It would be better to use a dropdown, which lets you select the allowed contents of the parameters. This can be achieved via Documentation.AllowedValues as part of the metadata record of the specific parameter.

Adding allowed values to parameter SO, Power Query, Power BI Desktop
Adding allowed values to parameter SO

What has a been a usual textbox before, now is a dropdown, with only the allowed values (and an empty value) to choose for the user.

Select the sort direction from the drop-down list, Power Query, Power BI Desktop
Select the sort direction from the drop-down list

These allowed values are static. They won’t change over time. But what if I need the allowed values to be dynamical?

Dynamically control Allowed Values of the parameters

Now let’s say I want to dynamically set the values to choose. What if I want the user to be able to choose only date values from the future?

Define date values dynamically for the future, Power Query, Power BI Desktop
Define date values dynamically for the future

What I do in the above script is the following:

  • I define the variable Tomorrow as todays date (DateTime.Date(DateTime.LocalNow())) plus 1 day ( + #duration(1,0,0,0))
  • In addition I define the allowed values for both, date1 and date2 as a dynamic list of 100 dates, starting from tomorrow, by using List.Dates(Tomorrow, 100, #duration(1,0,0,0))

The resulting documentation looks like this:

Selecting dates from a drop down list of allowed dates, Power Query, Power BI Desktop
Selecting dates from a drop-down list of allowed dates

As you can see in the screenshot above, the parameter date1 (and also date2, even it is not visible on the screenshot) got a different user interface. While I had a small calendar icon first, to choose a specific date, I now have a dropdown list with only the allowed values in it. See the difference here:

Different user interface for dates and dates with allowed values only, Power Query, Power BI Desktop
Different user interface for dates and dates with allowed values only

Adding more valuable information to the function parameters

In addition to Documentation.AllowedValues, there is some other information that can be added to the documentation of a custom functions parameters. Those are the following:

  • Documentation.FieldCaption:
  • Documentation.FieldDescription
  • Documentation.SampleValues

The following script uses the above mentioned fields within the metadata record:

Adding more description fields to the parameters of the custom M function, Power Query, Power BI Desktop
Adding more description fields to the parameters of the custom M function

The expectation is that these added fields in the metadata record will lead to more information in the documentation. However, a look at the documentation shows that this is unfortunately not the case:

Newly added description fields doen't appear in the user interface, Power Query, Power BI Desktop
Newly added description fields don’t appear in the user interface

Hmm, that wasn’t what I expected. I have only found one way to make the parameter documentation visible anyway: By removing the documentation of the function (not the parameter), which is the red marked part in the following screenshot:

Removing the functions documentation to see the documentation of the parameters, Power Query, Power BI Desktop
Removing the functions documentation to see the documentation of the parameters

By removing all the red marked part of the M script, the documentation for the parameters becomes visible (but of course the documentation of the function disappears):

This is how parameter description looks like, Power Query, Power BI Desktop
This is how parameter description looks like

For me it looks as if I always have to choose between the documentation of my function or the documentation of my function parameters. Both at the same time seems to be impossible, which of course makes little sense. But just because I couldn’t do it doesn’t mean that it can’t be done. If anyone out there has an idea of how it works, please say 🙂

My thanks go to the authors of the following excellent contributions on this topic: Chris Webb, Matt Masson, Imke Feldmann:

Regards from Germany,

Lars

I write my posts for you, the reader. Please take a minute to help me write my posts as well as possible. Thank you 🙂

[yasr_visitor_multiset setid=2]

Der Beitrag Writing documentation for custom M-functions, Part3 erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
https://ssbi-blog.de/blog/technical-topics-english/writing-documentation-for-custom-m-functions-part3/feed/ 14
Writing documentation for custom M-functions, Part2 https://ssbi-blog.de/blog/technical-topics-english/write-documentation-for-custom-m-functions-part2/ Sun, 04 Feb 2018 18:00:30 +0000 http://ssbi-blog.de/?p=2964 The good documentation of custom M functions is a key factor for efficiency in Power Query and Power BI Desktop. In my first post on this topic, I explained why documentation is important and how to add those to custom functions by changing metadata. If you haven’t read the previous article, you should do so […]

Der Beitrag Writing documentation for custom M-functions, Part2 erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
The good documentation of custom M functions is a key factor for efficiency in Power Query and Power BI Desktop. In my first post on this topic, I explained why documentation is important and how to add those to custom functions by changing metadata. If you haven’t read the previous article, you should do so before proceeding with this one here. In this post I show my favorite variant to add documentation to my custom functions. Have fun 🙂

You can download all code samples from here. If you already have my Power Query editor for Notepad++ (or want to build it) you can open the file in Notepad++. Otherwise open it in a simple text editor and paste it into the Advanced Editor of Power Query or Power BI Desktop. I will refer more frequently to the Microsoft Power Query for Excel Formula Language Specification. You can read it here.

Defining and adding metadata to the custom function – Version 2

In my previous post I defined a record, which then functioned as my metadata record. Then I changed the type of my custom function and in this step I added the new metadata record to my custom function. In this Version 2, which I prefer over Version 1,  I will explicitly define a new type function with its associated metadata record. This gives me greater flexibility to access the individual parameters of the function. This will be part of the third part of this series in a couple of weeks.

Metadata definition

This time, the definition of the metadata record doesn’t look different to Version 1, but I do not only define a metadata record, but a complete new type value. Take a look at the following screenshot:

Defining a new type value in M, including the metadata record, Power Query, Power BI Desktop
Defining a new type value in M, including the metadata record

What you can see is:

  1. The definition of a new type value fnType of type function. This type value contains all the parameters of my custom function, with their specific data types (date) and the data type of the function’s return value (list). Behind the definition of the type value you see the key word meta, which introduces the definition of the metadata record
  2. This is the definition of the metadata record, as you already know it from my previous post.

You might think: „And why is this his prefered version of adding documentation to a custom function? This looks much more difficult!“ This may be true, but this version allows me to modify the metadata not only for the custom function, but also for each parameter of the custom function. How this works and what it can be useful for, you will find out in the next post 🙂 If you want to dig deeper into the M type value system, take a look into the Microsoft Power Query for Excel Formula Language Specification, chapter 5 (Types). Now let’s add this type to my custom functon.

Adding metadata to the function

Adding this type (including the documentation) to my custom function is pretty easy:

Replacing the custom functions old type by the new one, including metadata, Power Query, Power BI Desktop
Replacing the custom functions old type by the new one, including metadata

At the end of the script I simply replace the type of my function fn by the newly created type fnType, using the function Value.ReplaceType(). The result is the same, compared to my previous post:

The result: The documentation of my custom M function, Power Query, Power BI Desktop
The result: The documentation of my custom M function

My next post will cover how you can document single parameters and also define allowed values. At this point using version 2 brings real added value.

Regards from Germany,

Lars

I write my posts for you, the reader. Please take a minute to help me write my posts as well as possible. Thank you 🙂

[yasr_visitor_multiset setid=2]

Der Beitrag Writing documentation for custom M-functions, Part2 erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
Writing documentation for custom M-functions, Part1 https://ssbi-blog.de/blog/technical-topics-english/writing-documentation-for-custom-m-functions-part1/ https://ssbi-blog.de/blog/technical-topics-english/writing-documentation-for-custom-m-functions-part1/#comments Tue, 16 Jan 2018 18:00:24 +0000 http://ssbi-blog.de/?p=2960 In a programming language such as M, with more than 630 functions, it is more than just useful if these functions are well documented. However, this also applies to custom functions in M. Even if there are already several articles on this topic, I hope that this article will help to create even more understanding. […]

Der Beitrag Writing documentation for custom M-functions, Part1 erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
In a programming language such as M, with more than 630 functions, it is more than just useful if these functions are well documented. However, this also applies to custom functions in M. Even if there are already several articles on this topic, I hope that this article will help to create even more understanding.

You can download all code samples from here. If you already have my Power Query editor for Notepad++ (or want to build it) you can open the file in Notepad++. Otherwise open it in a simple text editor and paste it into the Advanced Editor of Power Query or Power BI Desktop. I will refer more frequently to the Microsoft Power Query for Excel Formula Language Specification. You can download it here.

What is a documentation and why do I need one?

If you have already written your own custom functions in M, you surely know the value of a well-documented function. If not, take a look at the documentation of List.Sum():

Accessing the documentation of List.Sum(), Power Query, Power BI Desktop
Accessing the documentation of List.Sum()

By typing = List.Sum into the formula bar of a Power Query query you get the official documentation of this native M function. This documentation can provide the following information:

  • Name of the function
  • function description
  • the function parameters, including their names, data types and if they are optional or not
  • the syntax of the function and the data type of the returned value
  • an example on how to use the function

This information about the function structure and its use makes it much easier for the user to find the right one with currently more than 630 functions. It would therefore be very useful to be able to add such a documentation to a custom function. I’ll show you how to do that.

My tiny custom M function

The following custom function is the one to be documented in this post:

My custom function, Power Query, Power BI Desktop
My custom function
How the function works, Power Query, Power BI Desktop
How the function works

This function does the following: The function takes the two parameters date1 and date2 (both of type date) and creates a list of date values, starting with date1, up to and including date2.

I would like to add documentation for this function so that other users can use it more easily. This can also be very helpful for myself if I have written a lot of own functions. To add documentation to this function, I need to modify the metadata of the function. That’s why I would like to take a brief look at the subject of metadata.

Metadata

Metadata is additional data for a specific value, stored in a so called metadata record. Metadata is a large subject area and requires its own post (which I will write in near future). You can find an introduction to this topic under point 1.7 in the Power Query Formula Language Specification. Nevertheless, I would like to briefly discuss some of the key features here.

Metadata in general

As already mentioned, metadata is additional information that can be assigned to values (records, tables, etc.). These are stored in a single record. If no metadata is stored, the metadata record is empty. The stored metadata can be accessed with the function Value.Metadata(). An example certainly makes this more vivid:

Example for the usage of metadata in M, Power Query, Power BI Desktop
Example for the usage of metadata in M

This example shows the following steps:

  1. The initial situation: The base table with column Row, which contains the row numbers and column Values, which contains sample values.
  2. In this step I create a new column that contains the values, but also the row number that is stored within the metadata, by using the key word meta, followed by the metadata record.
  3. I delete the column Row, so that only the column Value + Metadata remains.
  4. I use the formula Value.Metadata([#"Value + Metadata"])[Row]to retrieve the row number information from the metadata.

The functions metadata

You can add pretty much anything you want to the metadata of your function, but there are some pretty interesting key words, that you should know. These key words will be displayed by Power Query in the function documentation and they are the following:

  • Documentation.Name
  • Documentation.LongDescription
  • Documentation.Description
  • Documentation.Examples

Keep that in mind: If you define Documentation.Description and Documentation.LongDescription, there will only be shown the LongDescription.

There are two versions of defining and adding metadata to a custom function, that I know about. I will start with the more common one.

Defining and adding metadata to the custom function – Version 1

If you search in forums or read blogs on this topic, you will most likely come across this version. I show them for the sake of completeness, because I prefer version number 2.

Metadata definition

As I mentioned before, metadata is stored in a record, so we have to define a record.

the metadata record, Power Query, Power BI Desktop
The metadata record

This record has the following fields:

  • Documentation.Name of type text,
  • Documentation.Description of type text,
  • Documentation.Example of type list. Type list is necessary, because you can save more than one example. This list is a list of records and the record’s fields are:
    • Description of type text; usually stores the same information as Documentation.Description;
    • Code of type text; here you can show how the usage of the function looks like;
    • Result of type text; Here you can show how an example return value of the function could look like.

My next task is to add this metadata to the function.

Adding metadata to the function

Now, that I have defined the metadata for my custom function, I want to add them to the function.

The complete function, Power Query, Power BI Desktop
The complete function (For complexity reasons the content of the metadata record has been removed)

Therefore I do the following steps:

  1. I wrap my original function in a further let-expression. Why do I do that? This gets important in step 3, where I want to overwrite the functions metadata. Therefore I need „access“ to the function itself. A characteristic feature of let-expression is that after that in all variables can be accessed, that are located between the let and the in. For detailed information about this behaviour, please read the following series of post, regarding the Environment concept in M.
  2. In this step I put in the metadata, which I already defined in my metadata record Documentation_Metadata. I removed the complete definition from this screenshot, to make it less complex. You will see the complete code at the end of this post.
  3. This step overwrites the metadata of my custom function fn with the newly defined metadata record Documentation_Metadata. Let us consider the function from the inside out.
    • Value.Type(fn)returns function, because the type of the custom function fn is function.
    • Value.ReplaceMetadata()replaces the input’s metadata information. The input is function and I replace the metadata of this type by my record Documentation_Metadata. The result is a type function with a new metadata record. This is important for the next step.
    • Value.ReplaceType()takes the function fn as first parameter and replaces the old type function with the new type function, which now has the metadata record inside.

Now that I have completed all the necessary steps, let’s take a look at the final result for this post.

The final result

I have taken all these steps to ensure that my custom function is adequately documented both for myself and for third parties. The following screenshot shows the result of my work and the transition from source code to help texts in Power Query.

The final result, Power Query, Power BI Desktop
The final result

In my next post I will show the version 2, my preferred variant to add a documentation to my custom functions.

Regards from Germany,

Lars

I write my posts for you, the reader. Please take a minute to help me write my posts as well as possible. Thank you 🙂

[yasr_visitor_multiset setid=2]

Der Beitrag Writing documentation for custom M-functions, Part1 erschien zuerst auf THE SELF-SERVICE-BI BLOG.

]]>
https://ssbi-blog.de/blog/technical-topics-english/writing-documentation-for-custom-m-functions-part1/feed/ 4