Pořadí vyhodnocení argumentů ve funkci CALCULATE

Funkce CALCULATE - Pořadí vyhodnocení argumentů

DAX je funkcionální jazyk, ve kterém při použití více funkcí vnořujeme jednotlivé funkce do sebe. Kdykoliv analyzujeme DAX kód, který obsahuje více vnořených funkcí, můžeme začít od nejvnitřnější funkce a postupovat směrem od středu k dalším vnějším funkcím. Jedinou výjimkou jsou funkce CALCULATE() a CALCULATETABLE()

Pořadí vyhodnocení filtrů ve funkci CALCULATE

V první řadě je dobré zmínit, že nezáleží na pořadí, v jakém píšeme filtry uvnitř funkce CALCULATE(). Všechny filtry napsané jako argumenty uvnitř funkce CALCULATE() jsou vyhodnoceny v logickém AND vztahu.  Níže uvedená měřítka proto vrací stejnou hodnotu.

Měřítka:

Prodeje (Bikes, FY2018) =
CALCULATE
(
    SUM(Sales[Sales Amount]),
    'Product'[Category] = "Bikes",
    'Date'[Fiscal Year] = "FY2018"
)

Prodeje (FY2018, Bikes) =
CALCULATE
(
    SUM(Sales[Sales Amount]),
    'Date'[Fiscal Year] = "FY2018",
    'Product'[Category] = "Bikes"    
)

Výsledkem obou měřítek je suma prodejů kol ve fiskálním roce 2018, samozřejmě s ohledem na případný vnější kontext, ve kterém mohou být měřítka vyhodnocena. 

Funkce CALCULATE - Pořadí vyhodnocení argumentů 2

Ve funkci CALCULATE() jsou dva typy argumentů. Prvním argumentem je výraz, který se má vyhodnotit, druhý a případné další argumenty jsou filtry, které ovlivňují výsledek prvního argumentu. Při psaní složitějších DAX výpočtů je dobré vědět, v jakém pořadí jsou tyto argumenty vyhodnoceny.

Pořadí vyhodnocení argumentů ve funkci CALCULATE

Funkce CALCULATE() má následující syntaxi.

Syntaxe funkce CACLULATE:

CALCULATE(<výraz>[, <filtr1> [, <filtr2> [, …]]])

První argument je povinný, a jedná se o výraz, který má být vyhodnocen. Dalšími argumenty jsou filtry, které jsou nepovinné a může jich být neomezený počet. Filtry jsou ve funkci CALCULATE() vyhodnoceny jako první v pořadí. Po sestavení nového kontextu filtru spolu s případnými vnějšími filtry dojde k vyhodnocení výrazu, který je uveden jako první argument funkce CALCULATE().

Pokud tedy vytvoříme měřítko, které obsahuje dvě vnořené funkce CALCULATE(), můžeme názorně vidět efekt výše popsaného pravidla.

Měřítko:

Vnořené funkce CALCULATE =
CALCULATE
(
CALCULATE
(
VALUES('Product'[Color]),
'Product'[Color] = "Blue"
),
'Product'[Color] = "Black"
)

Ve funkci VALUES() je uveden odkaz na sloupec obsahující názvy barev. Díky filtru nastavenému na jednu barvu máme jistotu, že VALUES() bude vracet tabulku s jedním řádkem a jedním sloupcem, která bude převedena automaticky na skalární hodnotu. Pokud bychom při analýze výše uvedeného kódu postupovali jako u všech ostatních DAX výrazů - tedy od nejvnitřnější funkce směrem k vnějším funkcím, pravděpodobně bychom řekli, že výsledkem bude černá barva. 

Vývojáře se zkušenostmi s SQL jazykem by možná napadlo, že výsledkem předchozího měřítka bude hodnota BLANK, protože se oba filtry navzájem vylučují. Výsledek pak může být překvapivý.

Funkce CALCULATE - Pořadí vyhodnocení argumentů 3

Jak bylo uvedeno dříve, při analýze funkcí CALCULATE() a CALCULATETABLE() musíme postupovat jinak, než u všech ostatních funkcí v jazyku DAX. Funkce CALCULATE() nejdříve vyhodnotí filtry, sestaví nový kontext filtru spolu se všemi vnějšími a vlastními filtry, a až následně dojde k vyhodnocení prvního argumentu funkce - výrazu který se má spočítat. Správná interpretace výše uvedeného kódu je proto následující.

V prvním kroku je vyhodnocen filtr ve vnější funkci CALCULATE(), který je na řádku číslo 9 a nastaví filtr na černou barvu. Následně dojde k vyhodnocení výrazu ve vnější CALCULATE() funkci. Výrazem, který se má vyhodnotit ve vnějším CALCULATE(), je vnitřní funkce CALCULATE(), která je na řádku 4 až 8. Vnitřní CALCULATE() v prvním kroku opět vyhodnotí nejdříve svůj filtr, nastavený na modrou barvu. Tento filtr přepíše původní vnější filtr, nastavený na černou barvu. Výraz ve vnitřní funkci CALCULATE() na řádku číslo 6 je proto vyhodnocen pod filtrem s modrou barvou. Výsledkem výrazu je proto hodnota "Blue".

Proč filtr ve vnitřní funkci CALCULATE přepíše vnější filtry

Pokud do funkce  CALCULATE() vložíme logický filtr, který má filtrovat konkrétní sloupec, dojde nejdříve k odstranění všech předchozích filtrů z tohoto sloupce. Proč dojde k odstranění všech předchozích filtrů z filtrovaného sloupce je zřejmé z následujícího DAX kódu, který obsahuje zápis stejného měřítka uvedeného v předchozím příkladu tak, jak je ve skutečnosti interpretováno při vyhodnocení.

Měřítko:

Vnořené funkce CALCULATE rozepsané =
CALCULATE
(
CALCULATE
(
VALUES('Product'[Color]),
FILTER
(
ALL('Product'[Color]),
'Product'[Color] = "Blue"
)
),
FILTER
(
ALL('Product'[Color]),
'Product'[Color] = "Black"
)
)

Logické filtry jsou ve funkci CALCULATE() vždy na pozadí při vyhodnocení přepsány do podoby tabulky. Zápis uvedený výše odpovídá původnímu měřítku. Došlo pouze k rozepsání filtrů do podoby, jak jsou ve skutečnosti interpretovány na pozadí při vyhodnocení měřítka. 

Nyní je tedy zřejmé, že před aplikováním filtru ve vnitřní funkci CALCULATE() dojde nejdříve k odstranění všech filtrů ze sloupce 'Product'[Color] díky funkci ALL(). Následně funkce FILTER() vrátí pouze ty hodnoty ze sloupce 'Product'[Color], které odpovídají filtru 'Product'[Color] = "Blue". Výsledným filtrem ovlivňujícím výraz ve vnitřní funkci CALCULATE() je tedy tabulka s jedním sloupcem a s jedním řádkem, obsahujícím hodnotu "Blue".

Funkce CALCULATE - Pořadí vyhodnocení argumentů 4

Jak je možné vidět na obrázku výše, obě měřítka vrací stejnou hodnotu. Dalším důležitým poznatkem, kromě pořadí vyhodnocení argumentů ve funkci CALCULATE() je, že filtry ve funkci CALCULATE() jsou vždy na pozadí přepsané do podoby tabulky. Tato tabulka je pak před vyhodnocením prvního argumentu ve funkci CALCULATE() přeměněna do podoby filtru, který je aplikován na celý model.

Shrnutí 

Pochopení pořadí vyhodnocení argumentů ve funkci CALCULATE() je velmi důležité a může výrazně usnadnit práci se složitějšími výrazy, které obsahují několik vnořených funkcí a mezi kterými mohou být i funkce CALCULATE() nebo CALCULATETABLE(). Funkce CALCULATE() může v některých situacích vracet neočekávané výsledky. Tomu se můžeme vyhnout, pokud se seznámíme se všemi vlastnostmi funkcí, které používáme. Následně velmi brzy zjistíme, že vše funguje správně a psaní DAX výrazů se stane jednodušší.

č. 19

Komentáře