Freigeben über


DAX benutzerdefinierte Funktionen (Vorschau)

Hinweis

DAX Benutzerdefinierte Funktionen befinden sich derzeit in der Vorschau.

DAX Mit benutzerdefinierten Funktionen (USER-Defined Functions, UDFs) können Sie Logik packen DAX und wie jede andere Funktion wiederverwenden DAX . UDFs stellen ein neues FUNCTION Schlüsselwort, optionale Parameter (Skalar, Tabelle und Verweise) und Typüberprüfungshilfsprogramme vor, die die Erstellung sicherer und klarer machen. Nachdem Sie eine UDF definiert haben, können Sie sie in einem Measure, einer berechneten Spalte, einer visuellen Berechnung oder sogar in anderen benutzerdefinierten Funktionen verwenden. Benutzer können Geschäftsregeln zentralisieren, die Wartung verbessern und Berechnungen im Laufe der Zeit sicher weiterentwickeln. Funktionen sind erstklassige Modellobjekte, die Sie in der Abfrageansicht und inDAX der TMDL-Ansicht erstellen und verwalten können, und sie können im Modell-Explorer unter dem Knoten "Funktionen" angezeigt werden.

Aktivieren benutzerdefinierter Funktionen

So versuchen Sie UDFs in Desktop:

  1. Wechseln Sie zu "Dateioptionen>" und "Einstellungsoptionen">.
  2. Wählen Sie Vorschaufeatures aus, und überprüfen Sie DAX benutzerdefinierte Funktionen.
  3. Wählen Sie "OK" aus, und starten Sie Power BI Desktop neu .

Definieren und Verwalten von benutzerdefinierten Funktionen

Es gibt mehrere Speicherorte zum Definieren und Verwalten von Funktionen:

  • DAX Abfrageansicht (DQV). Definieren und Ändern von Funktionen in DQV. DQV umfasst auch Schnellabfragen im Kontextmenü (Auswerten, Definieren und Auswerten sowie alle Funktionen in diesem Modell definieren), um UDFs schnell zu testen und zu verwalten.
  • TMDL-Ansicht. UDFs können auch in TMDL erstellt und bearbeitet werden. Die TMDL-Ansicht enthält auch das Kontextmenü Skript TMDL zu.
  • Modell-Explorer. Vorhandene Funktionen können im Modell-Explorer unter dem Knoten "Funktionen" angezeigt werden.

Wenn Sie eine UDF definieren, befolgen Sie die folgenden Benennungsanforderungen:

Funktionsnamen:

  • Muss innerhalb des Modells wohlgeformt und einzigartig sein.
  • Kann Punkte für Namespacing (z. B. Microsoft.PowerBI.MyFunc) enthalten. Es kann nicht mit einem Punkt beginnen oder enden oder aufeinander folgende Punkte aufweisen.
  • Außer Punkten (.) können Namen nur alphanumerische Zeichen oder Unterstriche enthalten. Keine Leerzeichen oder Sonderzeichen zulässig.
  • Darf nicht mit eingebauten DAX Funktionen oder reservierten Wörtern in Konflikt stehen (z. B. messen, funktion, definieren).

Parameternamen:

  • Kann nur alphanumerische Zeichen oder Unterstriche enthalten. Zeiträume sind nicht zulässig.
  • Darf kein reserviertes Wort sein.

Verwenden der DAX Abfrageansicht

Sie können benutzerdefinierte Funktionen in der DAX Abfrageansicht definieren, aktualisieren und auswerten. Weitere Informationen zur DAX Abfrageansicht finden Sie in der DAX Abfrageansicht.

Allgemeines Formular

DEFINE
    /// Optional description above the function
    FUNCTION <FunctionName> = ( [ParameterName]: [ParameterType], ... ) => <FunctionBody>

Tipp

Verwenden Sie /// für Funktionsbeschreibungen. Einzeilige (//) oder mehrzeilige (/* */) Kommentare werden in IntelliSense-Funktionsbeschreibungen nicht angezeigt.

Beispiel: Einfache Steuerfunktion

DEFINE
    /// AddTax takes in amount and returns amount including tax
    FUNCTION AddTax = 
        ( amount : NUMERIC ) =>
            amount * 1.1

EVALUATE
{ AddTax ( 10 ) }
// Returns 11

Speichern im Modell

So speichern Sie eine UDF aus der DAX Abfrageansicht zum Modell:

  • Klicken Sie auf "Modell aktualisieren" mit Änderungen , um alle UDFs in der Abfrage zu speichern.
  • Oder klicken Sie auf "Modell aktualisieren": Fügen Sie oberhalb der definierten Funktion neue Funktion hinzu, um eine einzelne UDF zu speichern.

Screenshot der DAX Abfrageansicht in Power BI Desktop, wobei zwei Speicherorte hervorgehoben werden, an denen Sie eine benutzerdefinierte Funktion speichern können. Das erste ist das Updatemodell mit der Schaltfläche

Verwenden der TMDL-Ansicht

Sie können benutzerdefinierte Funktionen in der TMDL-Ansicht definieren und/oder aktualisieren. Weitere Informationen zur TMDL-Ansicht finden Sie in der TMDL-Ansicht.

Allgemeines Formular

createOrReplace
    /// Optional description above the function
    function <FunctionName> = ( [ParameterName]: [ParameterType], ... ) => <FunctionBody>

Beispiel: Einfache Steuerfunktion

createOrReplace
    /// AddTax takes in amount and returns amount including tax
    function AddTax = 
        (amount : NUMERIC) =>
            amount * 1.1

Speichern im Modell

Klicken Sie auf die Schaltfläche Übernehmen oben in der Ansicht, um alle UDFs aus dem Skript im Modell zu speichern.

Screenshot der TMDL-Ansicht in Power BI Desktop, in der die Schaltfläche "Anwenden" oben in der TMDL-Ansicht hervorgehoben wird. Dies ist der Ort, an dem Sie eine benutzerdefinierte Funktion speichern können.

Verwenden des TMDL-Skripts in einem Power BI-Projekt

UDFs sind auch beim Verwenden eines Power BI-Projekts im Semantikmodell-TMDL-Skript enthalten. Sie befinden sich im functions.tmdlDefinitionsordner .

Visual Studio Code-Screenshot eines Power BI-Projekts. Explorer ist für den Semantikmodellordner geöffnet.

Verwenden des Modell-Explorers

Sie können alle benutzerdefinierten Funktionen im Modell im Modell-Explorer unter dem Knoten "Funktionen" anzeigen. Weitere Informationen zum Modell-Explorer finden Sie im Modell-Explorer.

Modell-Explorer-Bereich in Power BI Desktop mit dem erweiterten Knoten

In DAX der Abfrageansicht können Sie Schnellabfragen im Kontextmenü einer UDF im Modell-Explorer verwenden, um Funktionen einfach zu definieren und auszuwerten.

Im Bereich

In der TMDL-Ansicht können Sie Funktionen per Drag & Drop in den Arbeitsbereich verschieben oder im Kontextmenü einer UDF im Modell-Explorer Script TMDL verwenden, um Skripts zu erzeugen.

Der Bereich

Verwenden von DMVs zum Untersuchen von UDFs

Sie können UDFs in Ihrem Modell mithilfe von dynamischen Verwaltungsansichten (Dynamic Management Views, DMVs) prüfen. Mit diesen Ansichten können Sie Informationen zu Funktionen abfragen, einschließlich UDFs.

Sie können die Funktion INFO.FUNKTIONEN verwenden, um die UDFs im Modell zu untersuchen. Um das Ergebnis nur auf UDFs einzuschränken, geben Sie den Parameter ORIGIN als 2 an.

EVALUATE INFO.FUNCTIONS("ORIGIN", "2")

Diese Abfrage gibt eine Tabelle aller UDFs zurück, die sich derzeit im Modell befinden, einschließlich name, Beschreibung und zugeordneter Metadaten.

Verwenden einer benutzerdefinierten Funktion

Nachdem eine UDF definiert und im Modell gespeichert wurde, können Sie sie aus Measures, berechneten Spalten, visuellen Berechnungen und anderen UDFs aufrufen. Dies funktioniert genauso wie das Aufrufen integrierter DAX Funktionen.

Aufrufen einer UDF in einem Maß

Verwenden Sie eine UDF in einem Measure, um wiederverwendbare Logik mit vollständigem Filterkontext anzuwenden.

Total Sales with Tax = AddTax ( [Total Sales] )

Das Beispielmaß wird in der folgenden Tabelle gezeigt:

Tabelle mit

Aufrufen einer UDF in einer berechneten Spalte

UDFs können in einer berechneten Spalte verwendet werden, um wiederverwendbare Logik auf jede Zeile in einer Tabelle anzuwenden.

Hinweis

Wenn Sie eine UDF in einer berechneten Spalte verwenden, stellen Sie sicher, dass die Funktion einen Skalar eines konsistenten Typs zurückgibt. Weitere Informationen finden Sie unter Parameter . Konvertieren Sie das Ergebnis bei Bedarf mit CONVERT oder ähnlichen Funktionen in den gewünschten Typ.

Sales Amount with Tax = CONVERT ( AddTax ( 'Sales'[Sales Amount] ), CURRENCY )

Wir können dieses Beispielmaß sehen, das in der folgenden Tabelle verwendet wird:

Tabelle mit Verkaufsbetrag und Verkaufsbetrag mit Steuern. Der Verkaufsbetrag mit Steuern ist hervorgehoben. Der Bereich

Aufrufen einer UDF in einer visuellen Berechnung

Sie können UDFs in einer visuellen Berechnung verwenden, um Logik direkt auf das visuelle Element anzuwenden. Weitere Informationen zu visuellen Berechnungen finden Sie unter Visuelle Berechnungen.

Hinweis

Visuelle Berechnungen funktionieren nur für Felder, die im visuellen Element vorhanden sind. Sie können nicht auf Modellobjekte zugreifen, die nicht Teil des visuellen Elements sind, und Sie können modellbezogene Objekte (z. B. Spalten oder Measures, die nicht im visuellen Element sind) in diesem Kontext nicht an eine UDF übergeben.

Sales Amount with Tax = AddTax ( [Sales Amount] )

Wir können dieses Beispielmaß in der folgenden Tabelle sehen:

Im Bearbeitungsmodus für visuelle Berechnungen. Tabelle mit Verkaufsbetrag und Verkaufsbetrag mit Steuern. Der Verkaufsbetrag mit Steuern ist hervorgehoben. Die visuelle Berechnungsformel für den Umsatzbetrag mit Steuern ist hervorgehoben.

Aufrufen einer UDF in einer anderen UDF

Sie können UDFs verschachteln, indem Sie eine Funktion aus einer anderen aufrufen. In diesem Beispiel definieren wir unsere einfache AddTax UDF und rufen sie in einer anderen UDF auf. AddTaxAndDiscount

DEFINE
    /// AddTax takes in amount and returns amount including tax
    FUNCTION AddTax = 
        ( amount : NUMERIC ) =>
            amount * 1.1

	FUNCTION AddTaxAndDiscount = 
        (
			amount : NUMERIC,
			discount : NUMERIC
		) =>
		    AddTax ( amount - discount )

EVALUATE
{ AddTaxAndDiscount ( 10, 2 ) }
// Returns 8.8

Die Parameter

DAX UDFs können null oder mehr Parameter akzeptieren. Wenn Sie Parameter für eine UDF definieren, können Sie optional Typhinweise für jeden Parameter angeben:

  • Typ: welche Art von Wert der Parameter akzeptiert (AnyVal, Scalar, , Tableoder AnyRef).
  • Untertyp (nur für Skalartyp): der spezifische skalare Datentyp (Variant, Int64, , Decimal, Double, String, DateTime, Booleanoder Numeric).
  • ParameterMode: Wenn das Argument ausgewertet wird (val oder expr).

Typenhinweise befinden sich in der Form: [type] [subtype] [parameterMode]

Sie können alle, einige oder keine dieser Typhinweise für jeden Parameter einschließen, um Ihre Funktionen sicherer und vorhersehbarer auf Anrufwebsites zu machen. Wenn Sie alles weglassen und einfach den Parameternamen schreiben, verhält es sich wie AnyVal val, d. h., das Argument wird sofort zur Aufrufzeit ausgewertet. Dies ist nützlich für einfache Funktionen.

Typ

Der Typ definiert die Kategorie des Arguments, das der Parameter akzeptiert, und ob er als Wert oder Ausdruck übergeben wird.

Es gibt zwei Typenfamilien in DAX UDF-Parametern: Werttypen und Ausdruckstypen:

  • Werttypen: Dieses Argument wird sofort ausgewertet (eifrige Auswertung), wenn die Funktion aufgerufen wird und der resultierende Wert an die Funktion übergeben wird.
    • AnyVal: Akzeptiert einen Skalar oder eine Tabelle. Dies ist die Standardeinstellung, wenn Sie den Typ für einen Parameter weglassen.
    • Scalar: Akzeptiert einen skalaren Wert (kann zusätzlich einen Untertyp hinzufügen).
    • Table: Akzeptiert eine Tabelle.
  • Ausdruckstypen: Dieses Argument übergibt einen nicht ausgewerteten Ausdruck (faule Auswertung). Die Funktion entscheidet, wann und in welchem Kontext sie ausgewertet werden soll. Dies ist erforderlich für Referenzparameter und nützlich, wenn Sie den Filterkontext steuern müssen (z. B. innerhalb CALCULATE). expr Typen können Verweise auf eine Spalte, eine Tabelle, einen Kalender oder eine Maßnahme sein.
    • AnyRef: Akzeptiert einen Bezug (eine Spalte, eine Tabelle, einen Kalender oder einen Messwert).

Subtyp

Mit dem Untertyp können Sie einen bestimmten Scalar Datentyp definieren. Wenn Sie einen Untertyp definieren, müssen Sie den Parameter nicht explizit als Scalar Typ definieren, wird dies automatisch angenommen.

Untertypen sind:

  • Variant: Akzeptiert beliebigen Skalar.
  • Int64: Akzeptiert eine ganze Zahl.
  • Decimal: Akzeptiert eine Dezimalzahl mit fester Genauigkeit (z. B. Währung oder Geld).
  • Double: Akzeptiert eine Gleitkommadezimalzahl.
  • String: Akzeptiert Text.
  • DateTime: Akzeptiert Datum/Uhrzeit.
  • Boolean: Akzeptiert TRUE/FALSE.
  • Numeric: Akzeptiert numerische Werte (Int64, Decimaloder Double Untertypen)

ParameterModus

ParameterMode steuert, wann und wo der Parameterausdruck ausgewertet wird. Diese lauten wie folgt:

  • val (eifrige Auswertung): Der Ausdruck wird einmal ausgewertet, bevor die Funktion aufruft wird. Der resultierende Wert wird dann an die Funktion übergeben. Dies ist üblich für einfache Skalar- oder Tabelleneingaben. Dies ist die Standardeinstellung, wenn Sie "parameterMode" für einen Parameter weglassen.
  • expr (faule Auswertung): Der Ausdruck wird innerhalb der Funktion ausgewertet, potenziell in einem anderen Kontext (z. B. Zeilenkontext oder Filterkontext) und möglicherweise mehrmals, wenn mehrfach oder innerhalb von Iterationen verwiesen wird. Dies ist für die Referenzparameter erforderlich und nützlich, wenn Sie den Kontext der Auswertung steuern müssen.

Der Scalar Typ kann entweder val oder expr. Verwenden Sie val, wenn der Skalar einmal im Kontext des Aufrufers ausgewertet werden soll. Verwenden Sie diese Funktion expr , wenn Sie die Auswertung zurückstellen und möglicherweise den Kontext innerhalb der Funktion anwenden möchten. Siehe Beispiel: Tabellenparameter als Beispiel.

Der AnyRef Typ muss expr sein, da seine Bezüge (Spalten, Tabellen, Measures usw.) im Kontext der Funktion ausgewertet werden müssen.

Beispiel: Typumwandlung

DEFINE
    /// returns x cast to an Int64
    FUNCTION CastToInt = (
            x : SCALAR INT64 VAL
        ) =>
        x

EVALUATE
{ CastToInt ( 3.4 ), CastToInt ( 3.5 ), CastToInt ( "5" ) }
// returns 3, 4, 5

Dies verwendet einen Scalar Typ, Int64 Untertyp und val ParameterMode für vorhersagbare Rundung und Text-zu-Zahlen-Koersion, und stellt sicher, dass alle Ausdrücke eifrig ausgewertet werden. Sie können dies auch erreichen, indem Sie einfach den Int64 Untertyp einschließen, wie im folgenden Beispiel dargestellt. Nicht numerische Zeichenfolgen führen zu einem Fehler.

DEFINE
    /// returns x as an Int64
    FUNCTION CastToInt = (
            x : INT64
        ) =>
        x

EVALUATE
{ CastToInt ( 3.4 ), CastToInt ( 3.5 ), CastToInt ( "5" ) }
// returns 3, 4, 5

Beispiel: Tabellenparameter (Wert vs Ausdruck)

Zur Veranschaulichung, wie sich der UDF-ParameterMode auf den Filterkontext auswirkt, betrachten Sie zwei Funktionen, die beide Zeilen in der Tabelle "Sales" zählen. Beide verwenden CALCULATETABLE(t, ALL('Date')) in ihren Körpern, aber ein Parameter wird als val (eifrige Auswertung) und der andere als expr (faule Auswertung) deklariert.

DEFINE
    /// Table val: receives a materialized table, context can't be changed
    FUNCTION CountRowsNow = (
            t : TABLE VAL
        ) =>
        COUNTROWS ( CALCULATETABLE ( t, ALL ( 'Date' ) ) )
    
    /// Table expr: receives an unevaluated expression, context CAN be changed
    FUNCTION CountRowsLater = (
            t : TABLE EXPR
        ) =>
        COUNTROWS ( CALCULATETABLE ( t, ALL ( 'Date' ) ) )

EVALUATE
{
    CALCULATE ( CountRowsNow ( 'Sales' ), 'Date'[Fiscal Year] = "FY2020" ),
    CALCULATE ( CountRowsLater ( 'Sales' ), 'Date'[Fiscal Year] = "FY2020" )
}
// returns 84285, 121253

CountRowsNow gibt nur die Anzahl der Verkäufe für FY2020 zurück. Die Tabelle "Umsatz" wird bereits nach dem Jahr gefiltert, bevor Sie die Funktion eingeben, sodass ALL('Date') innerhalb der Funktion keine Auswirkung hat.

CountRowsLater gibt die Anzahl der Verkäufe für alle Jahre zurück. Die Funktion empfängt einen nicht ausgewerteten Tabellenausdruck und wertet ihn unter ALL('Date')aus, wobei der externe Jahresfilter entfernt wird.

Typüberprüfung

Die Typüberprüfung in UDFs kann mit neuen und vorhandenen Typüberprüfungsfunktionen erfolgen, die Sie innerhalb des Funktionstexts aufrufen können, um den Laufzeittyp der übergebenen Parameter zu bestätigen. Auf diese Weise können UDFs Kontextsteuerelemente verwenden, Parameter vorab überprüfen, Eingaben vor der Berechnung normalisieren.

Hinweis

Bei expr ParameterMode-Parametern treten Typüberprüfungen auf, wenn der Parameter im Funktionstext referenziert wird (nicht zur Funktionsaufrufzeit).

Verfügbare Typüberprüfungsfunktionen

UDFs können die folgenden Funktionen verwenden, um skalare Werte zu testen. Jede Rückgabe TRUE/FALSE, je nachdem, ob der angegebene Wert zu diesem Typ gehört.

Kategorie Funktionen
Numerisch ISNUMERIC, ISNUMBER
Double ISDOUBLE
Ganze Zahl ISINT64, ISINTEGER
Decimal ISTDEZIMAL, ISTWÄHRUNG
String ISSTRING, ISTEXT
Boolean ISBOOLEAN, ISLOGICAL
Datum und Uhrzeit ISDATETIME

Beispiel: Überprüfen, ob der Parameter eine Zeichenfolge ist

DEFINE
    /// Returns the length of a string, or BLANK if not a string
    FUNCTION StringLength = (
            s
        ) =>
        IF ( ISSTRING ( s ), LEN ( s ), BLANK () )

EVALUATE
{ StringLength ( "hello" ), StringLength ( 123 ) }
// Returns: 5, BLANK

Dadurch werden Fehler vermieden, und Sie können entscheiden, wie die nicht-zeichenfolgen Eingaben in die Funktion behandelt werden (in diesem Beispiel wird BLANK zurückgegeben).

Beispiel: Akzeptieren mehrerer Parametertypen

DEFINE
    /// Helper 1: get currency name by int64 key
    FUNCTION GetCurrencyNameByKey = (
            k : INT64
        ) =>
        LOOKUPVALUE ( 'Currency'[Currency], 'Currency'[CurrencyKey], k )
    
    /// Helper 2: get currency name by string code
    FUNCTION GetCurrencyNameByCode = (
            code : STRING
        ) =>
        LOOKUPVALUE ( 'Currency'[Currency], 'Currency'[Code], code )
    
    /// Accepts key (int64) or code (string) and returns the currency name
    FUNCTION GetCurrencyName = (
            currency
        ) =>
        IF (
            ISINT64 ( currency ),
            GetCurrencyNameByKey ( currency ),
            GetCurrencyNameByCode ( currency )
        )

EVALUATE
{ GetCurrencyName ( 36 ), GetCurrencyName ( "USD" ) }
// returns "Euro", "US Dollar"

In diesem Beispiel wird gezeigt, wie Sie die Typüberprüfung in UDFs verwenden, um mehrere Eingabetypen sicher zu akzeptieren und ein einzelnes, vorhersagbares Ergebnis zurückzugeben. GetCurrencyName verwendet ein Argument, currencydas entweder ein Ganzzahlwährungsschlüssel oder ein Textwährungscode sein kann. Die Funktion überprüft den Argumenttyp mit ISINT64. Wenn die Eingabe eine ganze Zahl ist, ruft sie das Hilfsprogramm GetCurrencyNameByKey auf, das den Währungsnamen basierend auf dem Währungsschlüssel nachschlagen soll. Wenn die Eingabe keine ganze Zahl ist, ruft sie das Hilfsprogramm GetCurrencyNameByCode auf, das den Währungsnamen basierend auf dem Währungscode nachschlagen soll.

Gleichzeitiges Definieren mehrerer Funktionen

UDFs ermöglichen es Ihnen, mehrere Funktionen in einer einzelnen Abfrage oder einem einzigen Skript zu definieren, wodurch es einfach ist, wiederverwendbare Logik zu organisieren. Dies ist besonders hilfreich, wenn Sie verwandte Berechnungen oder Hilfsroutinen zusammen kapseln möchten. Funktionen können zusammen oder einzeln ausgewertet werden.

DEFINE
    /// Multiplies two numbers
    FUNCTION Multiply = (
            a,
            b
        ) =>
        a * b

    /// Adds two numbers and 1
    FUNCTION AddOne = (
            x,
            y
        ) =>
        x + y + 1

    /// Returns a random integer between 10 and 100
    FUNCTION RandomInt = () =>
        RANDBETWEEN ( 10, 100 )

EVALUATE
{ Multiply ( 3, 5 ), AddOne ( 1, 2 ), RandomInt () }
// returns 15, 4, 98

Erweitertes Beispiel: Flexible Währungsumrechnung

Um zu zeigen, wie DAX UDFs komplexere Logik verarbeiten können, betrachten wir ein Währungskonvertierungsszenario. In diesem Beispiel werden Typüberprüfungen und geschachtelte Funktionen verwendet, um einen bestimmten Betrag in eine Zielwährung zu konvertieren, indem entweder der durchschnittliche oder der Schlusskurs für ein bestimmtes Datum verwendet wird.

createOrReplace
	function ConvertDateToDateKey =  
		( 
			pDate: scalar variant 
		) => 
		YEAR ( pDate ) * 10000 + MONTH ( pDate ) * 100 + DAY ( pDate ) 
	
	function ConvertToCurrency = 
		( 
			pCurrency:scalar variant, 
			pDate: scalar variant, 
			pUseAverageRate: scalar boolean, 
			pAmount: scalar decimal 
		) => 
		var CurrencyKey = 
			EVALUATEANDLOG ( 
				IF ( 
					ISINT64 ( pCurrency ), 
					pCurrency, 
					CALCULATE ( 
						MAX ( 'Currency'[CurrencyKey] ), 
						'Currency'[Code] == pCurrency 
					) 
				) 
				, "CurrencyKey" 
			) 

		var DateKey = 
			EVALUATEANDLOG ( 
				SWITCH ( 
					TRUE, 
					ISINT64 ( pDate ), pDate, 
					ConvertDateToDateKey ( pDate ) 
				) 
				, "DateKey" 
			) 

		var ExchangeRate = 
			EVALUATEANDLOG ( 
				IF ( 
					pUseAverageRate, 
					CALCULATE ( 
						MAX ( 'Currency Rate'[Average Rate] ), 
						'Currency Rate'[DateKey] == DateKey, 
						'Currency Rate'[CurrencyKey] == CurrencyKey 
					), 
					CALCULATE ( 
					MAX ( 'Currency Rate'[End Of Day Rate] ), 
						'Currency Rate'[DateKey] == DateKey, 
						'Currency Rate'[CurrencyKey] == CurrencyKey 
					) 
				) 
				, "ExchangeRate" 
			) 

		var Result = 
			IF ( 
				ISBLANK ( pCurrency ) || ISBLANK ( pDate ) || ISBLANK ( pAmount ), 
				BLANK (), 
				IF ( 
					ISBLANK ( ExchangeRate ) , 
					"no exchange rate available", 
					ExchangeRate * pAmount 
				) 
			) 

		RETURN Result

Die ConvertToCurrency Funktion akzeptiert flexible Eingabetypen für Währung und Datum. Benutzer können entweder einen Währungsschlüssel oder einen Datumsschlüssel direkt bereitstellen oder einen Währungscode oder einen Standarddatumswert angeben. Die Funktion überprüft den Typ der einzelnen Eingaben und behandelt sie entsprechend: Wenn pCurrency es sich um eine ganze Zahl handelt, wird sie als Währungsschlüssel behandelt. Andernfalls geht die Funktion von einem Währungscode aus und versucht, den entsprechenden Schlüssel aufzulösen. pDate folgt einem ähnlichen Muster, wenn es sich um eine ganze Zahl handelt, wird es als Datumsschlüssel behandelt; andernfalls wird davon ausgegangen, dass es sich um einen Standarddatumswert handelt und mithilfe der ConvertDateToDateKey Hilfsfunktion in einen Datumsschlüssel konvertiert wird. Wenn die Funktion keinen gültigen Exchnage-Kurs ermitteln kann, wird die Meldung "Kein Wechselkurs verfügbar" zurückgegeben.

Diese Logik kann dann verwendet werden, um ein Measure wie "Gesamtumsatz in lokaler Währung" zu definieren.

Total Sales in Local Currency = 
ConvertToCurrency (
    SELECTEDVALUE ( 'Currency'[Code] ),
    SELECTEDVALUE ( 'Date'[DateKey] ),
    TRUE,
    [Total Sales]
)

Dies kann optional mit einer dynamischen Formatzeichenfolge kombiniert werden, um das Ergebnis im entsprechenden Währungsformat anzuzeigen.

CALCULATE (
    MAX ( 'Currency'[Format String] ),
    'Currency'[Code] == SELECTEDVALUE ( 'Currency'[Code] )
)

Ein Beispielergebnis ist im folgenden Screenshot zu sehen.

Tabelle mit vollständigem Datum, Währung, Gesamtumsatz in lokaler Währung und Gesamtumsatz.

Überlegungen und Einschränkungen

Benutzerdefinierte Funktionen befinden sich derzeit in der Vorschau, und beachten Sie bitte die folgenden Überlegungen und Einschränkungen:

Allgemein:

  • UDFs können im Dienst nicht verfasst oder modelliert werden DAX .

  • Eine UDF im Modell kann nicht ausgeblendet/eingeblendet werden.

  • UDFs können nicht in Anzeigeordner abgelegt werden.

  • Keine Schaltfläche 'Funktion erstellen' im Menüband.

  • UdFs können nicht mit Übersetzungen kombiniert werden.

  • UDFs werden in Modellen ohne Tabellen nicht unterstützt.

  • In der DAX Abfrageansicht gibt es keine Schnellabfrage zum "Definieren mit Referenzen".

  • Object-Level Security (OLS) wird nicht auf Funktionen übertragen oder umgekehrt. Betrachten Sie beispielsweise die folgende Funktion F , die sich auf gesichertes Maß MyMeasurebezieht:

    function F = () => [MyMeasure] + 42
    

    Wenn die MyMeasure unter Verwendung von Sicherheit auf Objektebene gesichert wird, wird die Funktion F nicht automatisch gesichert. Wenn F unter einer Identität ohne Zugriff auf MyMeasure ausgeführt wird, fungiert er so, als wäre MyMeasure nicht vorhanden. Es wird empfohlen, sichere Objekte nicht in den Bezeichnungen und Beschreibungen von Funktionen preiszugeben.

Definieren einer UDF:

  • Rekursion oder gegenseitige Rekursion wird nicht unterstützt.
  • Funktionsüberladungen werden nicht unterstützt.
  • Explizite Rückgabetypen werden nicht unterstützt.

UDF-Parameter:

  • Optionale Parameter werden nicht unterstützt.
  • Parameterbeschreibungen werden nicht unterstützt.
  • UDFs können keinen enum Wert zurückgeben. Integrierte Funktionen, die enum-Werte als Funktionsparameter akzeptieren, können in diesem Kontext keine UDFs verwenden.
  • Ungebundene Parameter des Typhinweiss expr werden nicht ausgewertet.

IntelliSense-Unterstützung:

  • Obwohl UDFs in Live Connect- oder Verbundmodellen verwendet werden können, gibt es keine IntelliSense-Unterstützung.
  • Obwohl UDFs in visuellen Berechnungen verwendet werden können, verfügt die Bearbeitungsleiste für visuelle Berechnungen über keine IntelliSense-Unterstützung für UDFs.
  • Die TMDL-Ansicht bietet keine ordnungsgemäße IntelliSense-Unterstützung für UDFs.

Bekannte Fehler

Die folgenden Probleme sind derzeit bekannt und können sich auf die Funktionalität auswirken:

  • Verweise auf ein tabellarisches Modellobjekt (z. B. Measure, Tabelle, Spalte) in einer UDF werden nicht automatisch aktualisiert, wenn diese Objekte umbenannt werden. Wenn Sie ein Objekt umbenennen, von dem eine UDF abhängt, enthält der Funktionstext weiterhin den alten Namen. Sie müssen den UDF-Ausdruck manuell bearbeiten, um alle Verweise auf das umbenannte Objekt zu aktualisieren.
  • Bestimmte erweiterte Szenarien mit UDFs können zu Parserinkonsistenzen führen. Benutzer können beispielsweise rote Unterstreichungen oder Überprüfungsfehler sehen, wenn Spalten als expr Parameter übergeben oder nicht qualifizierte Spaltenverweise verwendet werden.