Udostępnij za pomocą


DAX funkcje zdefiniowane przez użytkownika (wersja zapoznawcza)

Uwaga / Notatka

DAX Funkcje zdefiniowane przez użytkownika są obecnie dostępne w wersji zapoznawczej.

DAX Funkcje zdefiniowane przez użytkownika (UDF) umożliwiają pakowanie DAX logiki i ponowne używanie jej tak jak każda inna DAX funkcja. Funkcje zdefiniowane przez użytkownika wprowadzają nowe FUNCTION słowo kluczowe, opcjonalne parametry (skalarne, tablicowe i referencyjne) oraz narzędzia pomocnicze dla sprawdzania typów, które sprawiają, że tworzenie jest bezpieczniejsze i jaśniejsze. Po zdefiniowaniu UDF można ją używać w miarze, kolumnie obliczeniowej, obliczeniach wizualnych lub nawet innych funkcjach zdefiniowanych przez użytkownika. Użytkownicy mogą centralizować reguły biznesowe, zwiększać łatwość konserwacji i bezpiecznie rozwijać obliczenia w czasie. Funkcje to obiekty modelu pierwszej klasy, którymi można tworzyć w widoku zapytań i widoku TMDL oraz zarządzać nimiDAX. Można je wyświetlić w Eksploratorze modeli w węźle Funkcje.

Włączanie funkcji zdefiniowanych przez użytkownika

Aby wypróbować funkcje zdefiniowane przez użytkownika w programie Desktop:

  1. Przejdź do pozycji Opcje pliku > i opcje ustawień>.
  2. Wybierz pozycję Funkcje w wersji zapoznawczej i sprawdź DAX funkcje zdefiniowane przez użytkownika.
  3. Wybierz przycisk OK i uruchom ponownie program Power BI Desktop.

Definiowanie funkcji zdefiniowanych przez użytkownika i zarządzanie nimi

Istnieje kilka lokalizacji do definiowania funkcji i zarządzania nimi:

  • DAX widok zapytania (DQV). Definiowanie i modyfikowanie funkcji w DQV. Funkcja DQV zawiera również menu kontekstowe Szybkie zapytania (Ocena, Definiowanie i ocenianie oraz Definiowanie wszystkich funkcji w tym modelu), które ułatwiają szybkie testowanie funkcji zdefiniowanych przez użytkownika i zarządzanie nimi.
  • Widok TMDL. Funkcje UDF można również tworzyć i edytować w TMDL. Widok TMDL zawiera również pozycję menu kontekstowego Skrypt TMDL do.
  • Eksplorator modelu. Istniejące funkcje można wyświetlić w węźle Funkcje w Eksploratorze modeli.

Podczas definiowania funkcji zdefiniowanej przez użytkownika (UDF) należy przestrzegać następujących wytycznych dotyczących nazewnictwa:

Nazwy funkcji:

  • Musi być dobrze sformułowany i unikatowy w modelu.
  • Może zawierać kropki (kropki) w celu nadania nazw (np. Microsoft.PowerBI.MyFunc). Nie można rozpocząć ani zakończyć kropką lub mieć kolejnych okresów.
  • Oprócz kropek nazwy mogą zawierać tylko znaki alfanumeryczne lub znak podkreślenia. Spacje ani znaki specjalne nie są dozwolone.
  • Nie może powodować konfliktu z wbudowanymi DAX funkcjami ani słowami zarezerwowanymi (np. miarą, funkcją, definiowaniem).

Nazwy parametrów:

  • Może zawierać tylko znaki alfanumeryczne lub podkreślenia. Okresy są niedozwolone.
  • Nie może być słowem zastrzeżonym.

Korzystanie z DAX widoku zapytania

W widoku zapytania można definiować, aktualizować i oceniać funkcje DAX zdefiniowane przez użytkownika. Aby uzyskać dodatkowe informacje na DAX temat widoku zapytania, zobacz DAX widok zapytania.

Formularz ogólny

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

Wskazówka

Użyj /// do opisów funkcji. Komentarze jednowierszowe (//) lub wielowierszowe (/* */) nie będą wyświetlane w opisach funkcji IntelliSense.

Przykład: Prosta funkcja podatkowa

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

EVALUATE
{ AddTax ( 10 ) }
// Returns 11

Zapisywanie do modelu

Aby zapisać funkcję zdefiniowaną przez użytkownika z DAX widoku zapytań do modelu:

  • Kliknij Aktualizuj model ze zmianami, aby zapisać wszystkie funkcje UDF w zapytania.
  • Możesz też kliknąć pozycję Aktualizuj model: Dodaj nową funkcję powyżej zdefiniowanej funkcji, aby zapisać pojedynczą funkcję zdefiniowaną przez użytkownika.

DAX Zrzut ekranu przedstawiający widok zapytania w programie Power BI Desktop z wyróżnionymi dwiema lokalizacjami, w których można zapisać funkcję zdefiniowaną przez użytkownika. Pierwszym z nich jest przycisk Aktualizuj model ze zmianami w górnej części widoku. Drugi to wiersz stanu w edytorze kodu z etykietą Aktualizuj model: Dodawanie nowej funkcji

Korzystanie z widoku TMDL

W widoku TMDL można definiować i/lub aktualizować funkcje zdefiniowane przez użytkownika. Aby uzyskać dodatkowe informacje na temat widoku TMDL, zobacz widok TMDL.

Formularz ogólny

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

Przykład: Prosta funkcja podatkowa

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

Zapisywanie do modelu

Kliknij przycisk Zastosuj na górze widoku, aby zapisać wszystkie UDF-y z skryptu do modelu.

Zrzut ekranu przedstawiający widok TMDL w programie Power BI Desktop z wyróżnionym przyciskiem Zastosuj w górnej części widoku. Jest to lokalizacja, w której można zapisać funkcję zdefiniowaną przez użytkownika.

Używanie skryptu TMDL w projekcie usługi Power BI

Funkcje UDF są również uwzględniane w skrypcie TMDL modelu semantycznego podczas korzystania z projektu Power BI. Można je znaleźć w functions.tmdl folderze definicji .

Zrzut ekranu programu Visual Studio Code przedstawiający projekt usługi Power BI. Eksplorator jest otwarty w folderze modelu semantycznego. Plik

Korzystanie z eksploratora modelu

Wszystkie funkcje zdefiniowane przez użytkownika można wyświetlić w modelu z poziomu Eksploratora modeli w węźle Funkcje . Aby uzyskać dodatkowe informacje na temat Eksploratora modeli, zobacz Eksplorator modeli.

Panel Eksploratora modeli w programie Power BI Desktop przedstawiający rozwinięty węzeł Funkcje. Wyświetlane są trzy funkcje zdefiniowane przez użytkownika: AddTax, AverageOrderValue i CustomerLifetimeValue.

W DAX widoku zapytania można użyć szybkich zapytań w menu kontekstowym (prawym przyciskiem myszy) funkcji UDF w Eksploratorze modeli, aby łatwo definiować i oceniać funkcje.

Okienko Eksplorator modeli w programie Power BI Desktop wyświetla rozwinięty węzeł Funkcje. Otwarte są dwa menu kontekstowe: pierwsze menu zawiera szybkie zapytania, Zmień nazwę, Usuń z modelu, Ukryj w widoku raportu, Odkryj wszystkie, Zwiń wszystko i Rozwiń wszystko. Szybkie zapytania są wyróżnione i zaznaczone. Drugie menu jest wyróżnione i oferuje opcje Szybkie zapytania Oceń, Zdefiniuj i oceń, Zdefiniuj nową funkcję i Zdefiniuj wszystkie funkcje w tym modelu.

W widoku TMDL można przeciągać i upuszczać funkcje na kanwie lub użyć opcji generowania skryptu TMDL w menu po kliknięciu prawym przyciskiem myszy na funkcję zdefiniowaną przez użytkownika w Eksploratorze modeli, aby wygenerować skrypty.

Okienko Eksplorator modeli w programie Power BI Desktop wyświetla rozwinięty węzeł Funkcje. Otwarte są dwa menu kontekstowe: pierwsze menu zawiera polecenia Skrypt TMDL do, Zmień nazwę, Usuń z modelu, Ukryj w widoku raportowania, Odkryj wszystko, Zwiń wszystko i Rozwiń wszystko. Skrypt do TMDL jest wyróżniony i wybrany. Drugie menu jest wyróżnione i oferuje opcje Skrypt do TMDL: karta Skrypt i Schowek.

Używanie widoków DMV do sprawdzania funkcji zdefiniowanych przez użytkownika

Funkcje zdefiniowane przez użytkownika można sprawdzić w modelu, korzystając z Dynamicznych Widoków Zarządzania (DMVs). Te widoki umożliwiają wykonywanie zapytań dotyczących funkcji, w tym funkcji zdefiniowanych przez użytkownika.

Możesz użyć funkcji INFO.FUNCTIONS do sprawdzenia UDF-ów w modelu. Aby ograniczyć wynik tylko do funkcji zdefiniowanych przez użytkownika, należy podać parametr ORIGIN jako 2.

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

To zapytanie zwraca tabelę wszystkich funkcji zdefiniowanych przez użytkownika aktualnie w modelu, w tym ich nazwę, opis i skojarzone metadane.

Korzystanie z funkcji zdefiniowanej przez użytkownika

Po zdefiniowaniu i zapisaniu funkcji zdefiniowanej przez użytkownika (UDF) w modelu, można ją wywołać z miar, kolumn obliczeniowych, obliczeń wizualnych oraz innych funkcji zdefiniowanych przez użytkownika. Działa to tak samo jak wywoływanie wbudowanych DAX funkcji.

Wywoływanie funkcji zdefiniowanej przez użytkownika w miarze

Użyj UDF w mierze, aby zastosować logikę z pełnym kontekstem filtru.

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

Przykładowa miara jest pokazana w poniższej tabeli:

Tabela przedstawiająca łączną sprzedaż i łączną sprzedaż z podatkiem. Wyróżniono łączną sprzedaż z podatkiem. Okienko wizualizacji jest otwarte. Kolumna łącznej sprzedaży z podatkiem jest wyróżniona w polu Kolumny.

Wywoływanie UDF (funkcji zdefiniowanej przez użytkownika) w kolumnie obliczeniowej

Funkcje zdefiniowane przez użytkownika (UDF) mogą być używane w kolumnie obliczeniowej w celu zastosowania logiki wielokrotnego użytku do każdego wiersza w tabeli.

Uwaga / Notatka

W przypadku korzystania z funkcji zdefiniowanej przez użytkownika w kolumnie obliczeniowej upewnij się, że funkcja zwraca skalar spójnego typu. Aby uzyskać więcej informacji, zobacz Parametry . W razie potrzeby przekonwertuj wynik na żądany typ przy użyciu CONVERT lub podobnych funkcji.

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

Poniższa przykładowa miara jest używana w poniższej tabeli:

Tabela przedstawiająca kwotę sprzedaży i kwotę sprzedaży z podatkiem. Kwota sprzedaży z podatkiem jest wyróżniona. Okienko wizualizacji jest otwarte. Kwota sprzedaży z podatkiem jest wyróżniona w polu kolumny.

Wywoływanie funkcji zdefiniowanej przez użytkownika w obliczeniach wizualnych

Funkcje UDF można użyć w wizualnych obliczeniach, aby zastosować logikę bezpośrednio w wizualizacji. Aby uzyskać dodatkowe informacje na temat obliczeń wizualnych, zobacz Obliczenia wizualne.

Uwaga / Notatka

Obliczenia wizualne działają tylko na polach znajdujących się w wizualizacji. Nie mogą oni uzyskać dostępu do obiektów modelu, które nie są częścią wizualizacji. Przekazywanie obiektów modelu (takich jak kolumny lub miary niewchodzące w skład wizualizacji) do funkcji zdefiniowanej przez użytkownika w tym kontekście jest niedozwolone.

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

Poniższa przykładowa miara jest widoczna w poniższej tabeli:

W trybie edycji obliczeń wizualnych. Tabela przedstawiająca kwotę sprzedaży i kwotę sprzedaży z podatkiem. Kwota sprzedaży z podatkiem jest wyróżniona. Formuła obliczeń wizualnych dla kwoty sprzedaży z podatkiem jest wyróżniona.

Wywoływanie funkcji zdefiniowanej przez użytkownika w innej funkcji zdefiniowanej przez użytkownika

Funkcje zdefiniowane przez użytkownika można zagnieżdżać, wywołując jedną funkcję w ramach innej. W tym przykładzie definiujemy naszą prostą AddTax UDF i wywołujemy ją w innym UDF, 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

Parametry

DAX Funkcje zdefiniowane przez użytkownika mogą akceptować zero lub więcej parametrów. Podczas definiowania parametrów dla funkcji zdefiniowanej przez użytkownika można opcjonalnie określić wskazówki dotyczące typu dla każdego parametru:

  • Typ: jakiego typu wartość przyjmuje parametr (AnyVal, Scalar, , Tablelub AnyRef).
  • Podtyp (tylko dla typu skalarowego): określony typ danych skalarnych (Variant, Int64, DecimalDoubleStringDateTimeBooleanlub ).Numeric
  • ParameterMode: kiedy argument jest oceniany (val lub expr).

Wskazówki dotyczące typów są w postaci: [type] [subtype] [parameterMode]

Możesz uwzględnić wszystkie, niektóre lub żadne z tych wskazówek typu dla każdego parametru, aby funkcje były bezpieczniejsze i bardziej przewidywalne w lokacjach wywołań. Jeśli pominiesz wszystko i po prostu napisz nazwę parametru zachowuje się jako AnyVal val, co oznacza, że argument jest obliczany natychmiast w czasie wywołania. Jest to przydatne w przypadku prostych funkcji.

Typ

Typ definiuje kategorię argumentu, który akceptuje parametr i czy jest przekazywany jako wartość , czy wyrażenie.

Istnieją dwie rodziny typów w DAX parametrach UDF: typy wartości i typy wyrażeń:

  • Typy wartości: ten argument jest obliczany natychmiast (gorliwe obliczanie) w momencie wywołania funkcji, a wynikowa wartość jest przekazywana do funkcji.
    • AnyVal: akceptuje wartość skalarną lub tabelę. Jest to ustawienie domyślne, jeśli pominięto typ parametru.
    • Scalar: akceptuje wartość skalarną (może dodatkowo dodać podtyp).
    • Table: akceptuje tabelę.
  • Typy wyrażeń: ten argument przekazuje niewartościowane wyrażenie (leniwe wyliczanie). Funkcja decyduje, kiedy i w jakim kontekście należy ją ocenić. Jest to wymagane w przypadku parametrów referencyjnych i przydatne, gdy trzeba kontrolować kontekst filtra (np. wewnątrz CALCULATE elementu). expr typy mogą być odwołaniami do kolumny, tabeli, kalendarza lub miary.
    • AnyRef: Przyjmuje odniesienie (kolumna, tabela, kalendarz lub miara).

Podtyp

Podtyp umożliwia zdefiniowanie określonego Scalar typu danych. Jeśli zdefiniujesz podtyp, nie musisz jawnie definiować parametru jako Scalar typu, przyjmuje się to automatycznie.

Podtypy to:

  • Variant: akceptuje wszelkie skalarne.
  • Int64: akceptuje liczbę całkowitą.
  • Decimal: akceptuje wartość dziesiętną o stałej precyzji (na przykład Waluta lub Pieniądze).
  • Double: akceptuje liczbę zmiennoprzecinkową.
  • String: akceptuje tekst.
  • DateTime: akceptuje datę/godzinę.
  • Boolean: akceptuje TRUE/FALSE.
  • Numeric: akceptuje dowolną wartość liczbową (Int64, Decimallub Double podtypy)

ParametrMode

ParametrMode określa, kiedy i gdzie wyrażenie parametru jest oceniane. Są to:

  • val (eager evaluation): Wyrażenie jest oceniane raz przed wywołaniem funkcji. Wynikowa wartość jest następnie przekazywana do funkcji. Jest to typowe dla prostych danych wejściowych skalarnych lub wejściowych tabeli. Jest to ustawienie domyślne, jeśli pominięto parametr parameterMode dla parametru.
  • expr (ocena leniwa): Wyrażenie jest obliczane wewnątrz funkcji, potencjalnie w innym kontekście (np. kontekście wiersza lub kontekście filtru) i ewentualnie wielokrotnie, jeśli jest do niego odwoływane wiele razy lub wewnątrz iteracji. Jest to wymagane w przypadku parametrów referencyjnych i przydatnych, gdy trzeba kontrolować kontekst oceny.

Typ Scalar może używać elementu val lub expr. Użyj val jeśli chcesz, aby skalar był obliczony raz w kontekście obiektu wywołującego. Użyj expr , gdy chcesz odroczyć wykonanie i ewentualnie zastosować kontekst wewnątrz funkcji. Zobacz Przykład: parametr tabeli jako przykład.

Typ AnyRef musi być expr, ponieważ jego odwołania (kolumny, tabele, miary itp.) muszą być oceniane w kontekście funkcji.

Przykład: rzutowanie typu

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

To używa typu Scalar, podtypu Int64 i trybuParametru val do przewidywalnego zaokrąglania i konwersji tekstu na liczbę, a także zapewnienia, że wszystkie wyrażenia są oceniane natychmiast. Można to również osiągnąć, dołączając tylko podtyp Int64, jak pokazano w poniższym przykładzie. Ciągi znaków nie będących liczbami spowodują błąd.

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

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

Przykład: Parametr tabeli (wartość a wyrażenie)

Aby zilustrować, jak parameterMode w UDF wpływa na kontekst filtru, rozważ dwie funkcje, które obie zliczają wiersze w tabeli "Sales". Oba używają CALCULATETABLE(t, ALL('Date')) w swoich ciałach, ale jeden parametr jest zadeklarowany jako val (chętna ocena) i drugi jako expr (leniwe obliczanie):

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 zwraca liczbę transakcji sprzedaży tylko dla roku fiskalnego 2020. Tabela "Sales" jest już filtrowana według roku przed wprowadzeniem funkcji, więc ALL('Date') wewnątrz funkcji nie ma żadnego wpływu.

Funkcja CountRowsLater zwraca liczbę sprzedaży ze wszystkich lat. Funkcja przyjmuje niewyrażone wyrażenie tabelowe i ocenia je w kontekście ALL('Date'), usuwając zewnętrzny filtr roku.

Sprawdzanie typów

Sprawdzanie typów w UDF-ach można wykonywać przy użyciu nowych i istniejących funkcji sprawdzania typów, które można wywołać wewnątrz treści funkcji, aby potwierdzić typ przekazywanych parametrów. Dzięki temu funkcje UDF mogą korzystać z kontroli kontekstu, weryfikować parametry z wyprzedzeniem oraz normalizować dane wejściowe przed obliczeniami.

Uwaga / Notatka

W przypadku expr parametrów parameterMode sprawdzanie typu występuje, gdy parametr jest przywoływał w treści funkcji (a nie w czasie wywołania funkcji).

Dostępne funkcje sprawdzania typów

UDF mogą używać następujących funkcji do testowania wartości skalarnych. Każdy zwracany TRUE/FALSE zależy od tego, czy podana wartość jest tego typu.

Kategoria Functions
Numeric ISNUMERIC, ISNUMBER
Double ISDOUBLE
Liczba całkowita ISINT64, ISINTEGER
Decimal ISDECIMAL, ISCURRENCY
Sznurek ISSTRING, ISTEXT
logiczny ISBOOLEAN, ISLOGICAL
Data i godzina ISDATETIME

Przykład: Sprawdzanie, czy parametr jest ciągiem

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

Zapobiega to błędom i pozwala zdecydować, jak obsługiwać dane wejściowe inne niż ciągi w funkcji (w tym przykładzie funkcja zwraca wartość BLANK).

Przykład: Akceptowanie wielu typów parametrów

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"

W tym przykładzie pokazano, jak używać sprawdzania typów w funkcjach zdefiniowanych przez użytkownika, aby bezpiecznie akceptować wiele typów danych wejściowych i zwracać jeden, przewidywalny wynik. GetCurrencyName przyjmuje jeden argument , currencyktóry może być kluczem waluty całkowitej lub kodem waluty tekstowej. Funkcja sprawdza typ argumentu za pomocą polecenia ISINT64. Jeśli dane wejściowe są liczbą całkowitą, wywołuje pomocnika GetCurrencyNameByKey , który wyszukuje nazwę waluty na podstawie klucza waluty. Jeśli dane wejściowe nie są liczbą całkowitą, wywołuje pomocnika GetCurrencyNameByCode , który wyszukuje nazwę waluty na podstawie kodu waluty.

Definiowanie wielu funkcji jednocześnie

Funkcje zdefiniowane przez użytkownika umożliwiają definiowanie kilku funkcji w jednym zapytaniu lub skrypcie, co ułatwia uporządkowanie logiki do wielokrotnego użytku. Jest to szczególnie przydatne, gdy chcesz grupować powiązane obliczenia lub procedury pomocnicze. Funkcje można oceniać razem lub indywidualnie.

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

Zaawansowany przykład: elastyczna konwersja walut

Aby pokazać, jak funkcje zdefiniowane przez użytkownika (UDF) mogą obsługiwać bardziej złożoną logikę, przyjrzymy się scenariuszowi konwersji waluty. W tym przykładzie użyto sprawdzania typów i zagnieżdżonych funkcji, aby przeliczyć daną kwotę na walutę docelową przy użyciu średniego lub całodobowego kursu wymiany dla określonej daty.

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

Funkcja ConvertToCurrency akceptuje elastyczne typy danych wejściowych zarówno dla waluty, jak i daty. Użytkownicy mogą podać klucz waluty lub klucz daty bezpośrednio albo podać kod waluty lub standardową wartość daty. Funkcja sprawdza typ poszczególnych danych wejściowych i odpowiednio je obsługuje: jeśli pCurrency jest liczbą całkowitą, jest traktowana jako klucz waluty; w przeciwnym razie funkcja przyjmuje kod waluty i próbuje rozpoznać odpowiedni klucz. pDate jest zgodny z podobnym wzorcem, jeśli jest liczbą całkowitą, jest traktowany jako klucz daty; w przeciwnym razie funkcja zakłada, że jest to standardowa wartość daty i jest konwertowana na klucz daty przy użyciu ConvertDateToDateKey funkcji pomocnika. Jeśli funkcja nie może określić prawidłowego kursu wymiany, zwraca komunikat "brak dostępnego kursu wymiany".

Tej logiki można następnie użyć do zdefiniowania miary, takiej jak Total Sales in Local Currency (Łączna sprzedaż w walucie lokalnej).

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

Można to opcjonalnie sparować z ciągiem formatu dynamicznego , aby wyświetlić wynik w odpowiednim formacie waluty.

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

Przykładowy wynik można zobaczyć na poniższym zrzucie ekranu.

Tabela przedstawiająca pełną datę, walutę, łączną sprzedaż w walucie lokalnej i łączną sprzedaż.

Uwagi i ograniczenia

Funkcje zdefiniowane przez użytkownika są obecnie w wersji zapoznawczej, a w wersji zapoznawczej należy pamiętać o następujących zagadnieniach i ograniczeniach:

Ogólne:

  • Nie można tworzyć ani modelować DAX funkcji zdefiniowanych przez użytkownika w usłudze.
  • Nie można ukrywać/odkrywać funkcji definiowanej przez użytkownika w modelu.
  • Nie można umieścić funkcji zdefiniowanych przez użytkownika w folderach widoku.
  • Brak przycisku „utwórz funkcję” na wstążce.
  • Nie można łączyć UDF z tłumaczeniami.
  • Funkcje zdefiniowane przez użytkownika (UDF) nie są obsługiwane w modelach bez tabel.

Tworzenie funkcji zdefiniowanej przez użytkownika:

  • Rekursja lub rekursja wzajemna nie jest obsługiwana.
  • Przeciążenie funkcji nie jest obsługiwane.
  • Jawne typy zwracane nie są obsługiwane.

Parametry funkcji zdefiniowanej przez użytkownika:

  • Parametry opcjonalne nie są obsługiwane.
  • Opisy parametrów nie są obsługiwane.
  • Funkcje definiowane przez użytkownika nie mogą zwracać wartości enum. Wbudowane funkcje, które akceptują wartości enum jako parametry swoich funkcji, nie będą mogły używać UDF w tym kontekście.
  • Nieprzypisane parametry dla podpowiedzi typu expr nie są oceniane.

Obsługa funkcji IntelliSense:

  • Chociaż funkcje zdefiniowane przez użytkownika mogą być używane w modelach z bezpośrednim połączeniem lub w modelach złożonych, nie ma wsparcia dla IntelliSense.
  • Chociaż funkcje UDF mogą być używane w obliczeniach wizualnych, pasek formuły obliczeń wizualnych nie obsługuje funkcji IntelliSense dla UDF.
  • Widok TMDL nie obsługuje prawidłowej funkcji IntelliSense dla funkcji UDF.

Znane usterki

Obecnie znane są następujące problemy i mogą mieć wpływ na funkcjonalność:

  • Odwołania do obiektu modelu tabelarycznego (np. miara, tabela, kolumna) w UDF nie są automatycznie aktualizowane po zmianie nazwy tych obiektów. Jeśli zmienisz nazwę obiektu, od którego zależy funkcja UDF, treść funkcji będzie nadal zawierać starą nazwę. Aby zaktualizować wszystkie odwołania do obiektu o zmienionej nazwie, należy ręcznie edytować wyrażenie UDF.
  • Niektóre zaawansowane scenariusze obejmujące funkcje zdefiniowane przez użytkownika mogą powodować niespójności w analizatorze. Na przykład użytkownicy mogą zobaczyć czerwone podkreślenia lub błędy walidacji podczas przekazywania kolumn jako expr parametrów lub przy użyciu niekwalifikowanych odwołań do kolumn.