Proměnné v jazyku DAX

Proměnné v DAX

Proměnné v jazyku DAX umožňují autorům tvořit přehlednější výpočty, přináší možnost rozdělením kódu na jednotlivé dílčí části a v některých případech můžeme využitím proměných dosáhnout optimálnějších výpočtů. Proměnné jsou součástí jazyka DAX od roku 2015. To znamená, že například v Excelu 2010 nebo 2013 nemůžeme používat proměnné. Od verze Excelu 2016 jsou již proměnné v Power Pivotu v Excelu dostupné, stejně jako v Power BI nebo dalších pravidelně aktualizovaných nástrojích. 

Proměnné v DAX mají trochu jiný význam než v jiných programovacích jazycích. Proměnná v DAX slouží pouze k uložení výpočtu, a nemůže být následně nikdy přepsána. Další důležitou vlastností proměnných v DAX je způsob jejich vyhodnocení. Proměnné jsou vyhodnoceny pouze jednou, bez ohledu na to, kolikrát je v kódu použijeme, a jsou vyhodnoceny v kontextu, kde jsou definovány, ne kde jsou použity, viz příklady níže v článku. Současně, pokud definujeme proměnou, která nebude nikde v další části kódu použita, nebude výpočet v proměnné nikdy vyhodnocen.

(Aktualizováno 7. 1. 2023)

Definice proměnných

Proměnné můžeme definovat v jakémkoliv DAX výrazu. Klíčovým slovem pro definici proměnné je v jazyku DAX slovo VAR, za kterým následuje název proměnné a její definice. Proměnných můžeme definovat v rámci jednoho výrazu libovolné množství. Pro ukončení výrazu pak slouží klíčové slovo RETURN, za kterým následuje výsledek výrazu. Jednotlivé VAR - RETURN výrazy můžeme také vnořovat. To znamená, že uvnitř definice jedné proměnné můžeme definovat další proměnné, a výsledek vnitřní definice opět vypsat pomocí klíčového slova RETURN. 

Názvy proměnných nesmí začínat číslovkou, nesmí obsahovat žádné speciální znaky nebo znaky s diakritikou, nesmí být stejné jako jsou názvy tabulek v modelu a také se nesmí shodovat s názvy DAX funkcí.

Příklad použití VAR a RETURN

Příklady v tomto příspěvku jsou vytvořeny ve cvičném Power BI souboru Adventure Works DW 2020.pbix. V tomto souboru je navíc vytvořené měřítko [Prodeje], které vrací sumu za prodané produkty v aktuálním kontextu vyhodnocení.

Měřítko:

Prodeje = SUM(Sales[Sales Amount])

Použití proměnné v DAX kódu je relativně přímočaré. Zá klíčovým slovem VAR následuje název proměnné a její definice. Před vyvoláním dříve definované proměnné pak musíme uvést klíčové slovo RETURN následované výrazem, který bude výsledkem výpočtu. Jednotlivé VAR – RETURN výrazy můžeme také vnořovat. Začněme ale jednoduchým příkladem, následující výraz vrací sumu prodejů v aktuálním kontextu vyhodnocení.

Měřítko:

Prodeje proměnná =
VAR SumaProdeju = [Prodeje]
RETURN
    SumaProdeju

Ve výše uvedeném výpočtu si do mroměnné s názvem SumaProdeju uložíme hodnotu měřítka [Prodeje], kterou následně použijeme jako výsledek měřítka za klíčovým slovem RETURN. Výše uvedený výraz proto vrací stejný výsledek jako samotné měřítko [Prodeje]. Cílem tohoto příkladu je pouze znázornit syntaxi výrazu VAR – RETURN.

Proměnné v DAX 2

Další příklad již bude ukázkou možného vylepšení rychlosti vyhodnocení výpočtu využitím proměnných. Uvažujme například situaci, kdy chceme zobrazit hodnoty v jiném formátu, pokud výsledná hodnota přesáhne určitou hranici. 

Měřítko:

Prodeje v tis =
IF
(
    [Prodeje] >= 10000000,
    FORMAT([Prodeje]/1000,"# ##0.00 tis", "cs-cz"),
    [Prodeje]
)

Měřítko [Prodeje v tis] v prvním kroku ve funkci IF() vyhodnotí, zda je hodnota prodejů v aktuálním kontextu vyšší než 10 mil. Pokud ano, dojde k dělení hodnoty prodejů jedním tisícem a naformátování výsledného čísla podle druhého argumentu funkce FORMAT(). Pokud jsou prodeje nižší než 10 mil, výsledkem výpočtu bude originální hodnota měřítka [Prodeje]. Smyslem je tedy zobrazit velké částky (nad 10 mil) v jiném formátu. Takovéto měřítko asi zřídka kdy použijeme v reálném reportu, nicméně jedná se o ideální příklad pro znázornění optimalizace výpočtu pomocí proměnných, jak si ukážeme dále v alternativním výpočtu.

Proměnné v DAX 3

V měřítku  [Prodeje v tis] jsme třikrát použili stejné měřítko, které je ve všech třech případech vyvoláno ve stejném kontextu vyhodnocení. Pokud bychom nejdříve výsledek měřítka [Prodeje] uložili do proměnné, budeme mít jistotu, že výpočet bude vyhodnocen pouze jednou, bude uložen do proměnné, a následně bude použitý na třech místech ve výpočtu, bez nutnosti znovu vyhodnocovat stejný výpočet na různých místech ve funkci IF(). Definice měřítka následujcí výše popsanou logiku může vypadat následovně.

Měřítko:

Prodeje v tis proměnné =
VAR SumaProdeju = [Prodeje]
VAR Vysledek =
IF
(
    SumaProdeju >= 10000000,
    FORMAT(SumaProdeju/1000,"# ##0.00 tis", "cs-cz"),
    SumaProdeju
)
RETURN
    Vysledek

V měřítku [Prodeje v tis proměnné] je v prvním kroku definována proměnná s názvem SumaProdeju, ve které je uložena hodnota měřítka [Prodeje] v aktuální kontextu vyhodnocení. Tato proměná je pak použita na třech místech uvnitř další proměnné s názvem Vysledek. Oproti původnímu výpočtu je nyní měřítko [Prodeje] vyhodnoceno pouze jednou, hodnota je uložena do proměnné, a následně je třikrát použita ve funkci IF(), bez nutnosti znovu načítat hodnoty z modelu. Výsledek obou výpočtů je shodný, nicméně výpočet s použitím proměnných bude v tomto konkrétním příkladu pravděpodobně rychlejší.

Pozn.: DAX Engine, který běží na pozadí Power BI a jiných analytických nástrojů, může v některých specifických typech výpočtů provést na pozadí stejnou optimalizaci, pokud rozpozná, že je stejný výpočet ve stejném kontextu použitý vícekrát.

Proměnné v DAX 4

Vyhodnocení varianty výpočtu s použitím proměnných je rychlejší, protože měřítko [Prodeje] je vyhodnoceno pouze jednou, bez nutnosti opakovat stejný výpočet několikrát, jak tomu bylo u původního výpočtu bez použití proměnných.

Při práci s proměnnými musíme myslet na to, že proměnné jsou vyhodnoceny tam, kde jsou definovány, ne kde jsou vyvolány. Pro demonstraci této vlastnosti se podívejme na následující výpočet.

Měřítko:

Prodeje všechny kategorie =
CALCULATE
(
    [Prodeje],
    REMOVEFILTERS('Product'[Category])
)

Měřítko [Prodeje všechny kategorie] obsahuje funkci CALCULATE(), ve které před vyhodnocením měřítka [Prodeje] odstraňujeme všechny filtry ze sloupce 'Product'[Category].  Pokud měřítko použijeme ve vizuálu Tabulka s kategoriemi produktů v řádcích, filtr působící na výpočet v každém řádku tabulky bude odstraněn, díky funkci REMOVEFILTERS().

Proměnné v DAX 5

Pokud bychom nevěděli, že proměnná je vyhodnocena tam, kde je definována, tak bychom se mohli pokusit přepsat předchozí výpočet s použitím proměnných následujícím způsobem.

Měřítko:

Prodeje všechny kategorie (špatně) =
VAR SumaProdeju = [Prodeje]
VAR Vysledek =
    CALCULATE
    (
        SumaProdeju,
        REMOVEFILTERS('Product'[Category])
    )
RETURN
    Vysledek

Ve výše uvedeném výpočtu nemá funkce REMOVEFILTERS() ve druhém argumentu funkce CALCULATE() žádný vliv na výpočet proměnné SumaProdeju v prvním argumentu. Měřítko [Prodeje] je nyní vyhodnoceno mimo funkci CALCULATE(), tedy v místě a v kontextu, kde je definována proměnná s názvem SumaProdeju. Výsledek proto vypadá následovně.

Proměnné v DAX 6

Ačkoli výše uvedená ukázka vypadá jako nevýhoda proměnných, opak je pravdou. To, že je proměnná vyhodnocena v místě, kde je definována, je ve skutečnosti velkou výhodou a tato vlastnost výrazně zjednodušuje psaní DAX kódu.

Představme si například situaci, kdy potřebujeme přidat do tabulky produktů počítaný sloupec, obsahující kumulativní součet prodejů, postupně od produktu s nejvyšší částkou prodejů až po nejnižší. Takto definovaný sloupec může být základem například pro ABC analýzu produktů

Počítaný sloupec:

Prodeje Kumulativně =
VAR ProdejeAktualniProdukt = [Prodeje]
VAR ProduktyAProdeje =
    ADDCOLUMNS
    (
        'Product',
        "@ProdejeProduktu",
        [Prodeje]
    )
VAR ProdejeKumulativne =
    SUMX
    (
        FILTER
        (
            ProduktyAProdeje,
            [@ProdejeProduktu] >= ProdejeAktualniProdukt
        ),
        [@ProdejeProduktu]
    )
RETURN
   ProdejeKumulativne

V první proměnné ProdejeAktualniProdukt bude uložena suma za prodané produkty pro aktuální produkt v každém řádku tabulky 'Product'. Ve druhé proměnné ProduktyAProdeje je uložena kopie celé originální tabulky 'Product', se všemi produkty a novým počítaným sloupcem, který obsahuje prodeje sumu za prodeje každého produktu. Důležitý poznatek zde může být, že do proměnných můžeme ukládat také tabulky (proměnná s názvem ProduktyAProdeje). Ve třetí proměnné s názvem ProdejeKumulativně pak spočítáme kumulativní prodeje pro aktuální produkt, tedy sumu za prodeje všech produktů, které mají prodeje vyšší než aktuální produkt v originální tabulce nahrané v modelu. Celý výpočet je rozdělen pomocí proměnných do dílčích kroků, které by měly být samostatně relativně srozumitelné. Nyní se můžeme podívat na výpočet vracející stejné výsledky, ale bez použití proměnných.

Počítaný sloupec:

Prodeje kumulativně BEZ proměnných =
SUMX
(
    FILTER
    (
        ADDCOLUMNS('Product', "@ProdejeProduktu", [Prodeje]),
        [@ProdejeProduktu] >=
        CALCULATE
        (
            [Prodeje],
            ALL('Product'),
            'Product'[ProductKey] = EARLIER('Product'[ProductKey],2)
        )
    ),
    [@ProdejeProduktu]
)

Vysvětlovat každý detail ve verzi výpočtu bez proměnných by vydalo na samostatný příspěvek. Pozornost by však měla být směřována především na funkci CALCULATE(), ve které je nutné manipulovat s filtry tak, abychom dokázali z vnitřní iterace přistoupit k hodnotám ve vnější, originální tabulce 'Product', ve které je nový počítaný sloupec vytvořen. To je úkol, kterým se nemusíme při použití proměnných příliš zabývat, právě protože jsou proměnné vyhodnoceny tam, kde jsou definovány.

Výsledek obou verzí počítaného sloupce pak vrací kumulativní prodeje od produktu z nejvyšší sumou prodejů po nejnižší.

Proměnné v DAX 7

Jak je vidět na obrázku výše, obě verze výpočtu kumulativních prodejů vrací stejné výsledky, nicméně postup výpočtu je v obou případech rozdílný.

Shrnutí

Používání proměnných výrazně zjednodušuje psaní DAX kódu. V některých případech sice zápis výpočtu s použitím proměnných zabere více řádků kódu, nicméně benefitem je lepší čitelnost, možnost odladit si každý krok ve výpočtu samostatně a logické rozdělení složitějších výpočtů na dílčí jednodušší mezi výpočty. Další výhodou proměnných je způsob jejich vyhodnocení. Proměnné jsou vyhodnoceny tam, kde jsou definovány, a ne kde jsou použity. Můžeme si tak jednoduše uložit jeden výpočet v určitém kontextu vyhodnocení, a použít výsledek výpočtu uložený v proměnné v jiném kontextu vyhodnocení, například uvnitř iteračních funkcí. Zvyknout si používat proměnné může zabrat určitý čas, nicméně výhody jejich používání by měli převažovat.

č. 55

Komentáře