Jak fungují agregační funkce v jazyku DAX

Úvodní obrázek

Jazyk DAX obsahuje celou řadu agregačních funkcí, jejichž používání je v případě jednoduchých výpočtů relativně intuitivní. V některých složitějších vzorcích, zejména pak pokud používáme agregační funkce v kontextu řádku, mohou být výsledky těchto funkcí překvapivé. V tomto příspěvku si proto na jednoduchých příkladech vysvětlíme, jak agregační funkce fungují.

Jak fungují agregační funkce

Mezi běžně používané agregační funkce patří funkce jako SUM()COUNT(), DISTINCTCOUNT(), MAX()MIN(), AVERAGE() a další. Všechny tyto funkce mají několik společných jmenovatelů. Jako argumenty uvedených funkcí můžeme používat pouze existující sloupce v modelu, a výsledkem těchto funkcí je vždy agregovaná hodnota z použitého sloupce. Způsob agregace je pak odvozen od názvu funkce. 

Mezi agregační funkce ale řadíme také funkce pokročilejší, ve kterých můžeme v prvním argumentu definovat tabulku, a ve druhém argumentu výraz určený k agregaci. Mezi tyto funkce patří všechny funkce s X na konci jejich názvu. Jedná se například o funkce SUMX(), COUNTX(), MAXX(), MINX(), AVERAGEX() atd. Kompletní výpis všech agregačních funkcí je dostupný v oficiální dokumentaci. Příklady a vysvětlení některých vybraných DAX funkcí můžete najít v samostatných článcích na stránce DAX funkce.

V tomto příspěvku se pro zjednodušení zaměříme pouze na dvě funkce, a to na funkci SUM() a SUMX(). Všechny obecné principy ale platí i pro ostatní agregační funkce. Rozdíl je pak pouze v typu agregace, podle toho kterou funkci aktuálně potřebujeme použít.

Rozdíl mezi funkcí SUM a SUMX

Ačkoliv to při pohledu na syntaxi funkcí SUM() a SUMX() nemusí být úplně zřejmé, obě funkce fungují velmi podobně. Ve skutečnosti je totiž funkce SUM() pouze syntaktickou zkratkou pro funkci SUMX(). Uvažujme například následující měřítko, které bude vracet sumu za prodeje produktů v aktuálním kontextu vyhodnocení.

Měřítko:

Prodeje = SUM(Sales[Sales Amount])

Pomocí měřítka [Prodeje] sčítáme všechny hodnoty ze sloupce Sales[Sales Amount] dostupné v aktuálním kontextu vyhodnocení. Jak se chovají agregační funkce v kontextu řádku a v kontextu filtru si vysvětlíme později. Nejdříve si ale ukážeme druhou verzi měřítka [Prodeje], která bude vracet za všech okolností stejné hodnoty, nyní ale s použitím funkce SUMX().

Měřítko:

Prodeje (2) = SUMX(Sales, Sales[Sales Amount])

Pokud obě verze výpočtů vložíme do jakéhokoliv vizuálu s jakýmikoliv atributy, vždy budou vracet stejné výsledky.

Jak fungují agregační funkce v jazyku DAX

Měřítko [Prodeje] i měřítko [Prodeje (2)] vrací stejné hodnoty, protože na pozadí je funkce SUM() vyhodnocena pomocí funkce SUMX(), stejným způsobem jak je znázorněno u měřítek [Prodeje] a [Prodeje (2)]. Rozdíl mezi funkcí SUM() a funkcí SUMX() je pouze v tom, že pomocí funkce SUM() můžeme sčítat pouze hodnoty z jednoho konkrétního sloupce nahraného v modelu. Na druhou stranu pomocí funkce SUMX() můžeme sčítat jakékoliv hodnoty nebo výrazy, které jsou vyhodnoceny v kontextu řádku tabulky zadané v prvním argumentu. Pomocí funkce SUMX() tak můžeme tvořit pokročilejší výpočty, ve kterých můžeme mimo jiné pracovat s více sloupci z tabulky. Například můžeme násobit hodnoty ze dvou sloupců, a výsledky těchto mezivýpočtů poté sčítat.

Při rozhodování zda použít funkci SUM() nebo funkci SUMX() pak platí jednoduché pravidlo. Pokud sčítáme hodnoty z jednoho sloupce který je nahraný v existující tabulce v modelu, použijeme funkci SUM(), protože se jedná o jednodušší zápis než při použití funkce SUMX() pro stejný účel.

Pokud ale potřebujeme sečíst hodnoty které jsou výsledkem nějakého výpočtu, použijeme funkci SUMX(). Tím se můžeme vyhnout neustálému přidávání počítaných sloupců s jednoduchými mezivýpočty do tabulek v modelu, což zná asi každý z nás, protože to je typická praxe v začátcích práce s jazykem DAX.

Protože je chování funkcí SUM() i SUMX() při agregaci hodnot z jednoho sloupce shodné, v další části příspěvku budeme pro zjednodušení pracovat pouze s funkcí SUM(). Detailnější informace o funkcích SUM() a SUMX(), včetně dalších příkladů můžete najít v samostatném příspěvku.

Agregační funkce v kontextu řádku

Agregační funkce při vyhodnocení ignorují kontext řádku. Kontext řádku vzniká automaticky při vytvoření počítaného sloupce v existující tabulce v modelu nebo programově v iteračních funkcích. Tuto vlastnost si můžeme znázornit právě na příkladu vytvoření počítaného sloupce, ve kterém budeme v tabulce 'Sales' sčítat hodnoty ze sloupce 'Sales'[Sales Amount]. 

Počítaný sloupec:

Součet prodejů = SUM(Sales[Sales Amount])

Nový počítaný sloupec vrací v každém řádku tabulky stejnou hodnotu, která odpovídá součtu všech hodnot ze sloupce 'Sales'[Sales Amount].

Jak fungují agregační funkce v jazyku DAX 2

Důvod proč vrací funkce SUM() součet všech hodnot ze sloupce 'Sales'[Sales Amount] najdeme v kontextu vyhodnocení. Kontext vyhodnocení v počítaném sloupci je dán aktuálním kontextem řádku. Na druhou stranu, na výpočet v počítaném sloupci nepůsobí žádný kontext filtru. Protože agregační funkce ignorují kontext řádku, funkce SUM() jednoduše sečte všechny hodnoty ze sloupce 'Sales'[Sales Amount] v každém řádku tabulky.

Jiná situace ale nastane pokud použijeme funkci SUM() v měřítku, které bude vyhodnoceno v reportu, ve kterém na výpočet běžně působí filtry z různých vizuálů.

Agregační funkce v kontextu filtru

Pro znázornění chování agregačních funkcí v kontextu filtru můžeme použít již dříve vytvořené měřítko [Prodeje], které má následující definici.

Měřítko:

Prodeje = SUM(Sales[Sales Amount])

V měřítku [Prodeje] používáme funkci SUM() pro sečtení všech hodnot ze sloupce 'Sales'[Sales Amount]. Jedná se o stejný výpočet, který jsme použili pro vytvoření počítaného sloupce 'Sales'[Součet prodejů], kde jsme mohli vidět že výsledek tohoto počítaného sloupce byl v každém řádku tabulky stejný, a vracel součet za všechny hodnoty ze sloupce 'Sales'[Sales Amount].

Pokud měřítko [Prodeje] vložíme do vizuálu v reportu, a pokud na měřítko nebudou působit žádné filtry z řádků nebo os vizuálů nebo z panelu filtrů, výsledkem bude opět součet všech hodnot ze sloupce 'Sales'[Sales Amount].

Jak fungují agregační funkce v jazyku DAX 3

Pokud přidáme do řádků použitého vizuálu hodnoty ze sloupce s kategoriemi produktů, měřítko [Prodeje] bude vyhodnoceno v kontextu filtru každé kategorie.

Jak fungují agregační funkce v jazyku DAX 4

Funkce SUM() použitá v měřítku [Prodeje] je nyní vyhodnocena v kontextu filtru každé kategorie, a vrací proto sumu za prodeje pouze těch produktů, které patří do kategorie zobrazené v aktuálním řádku vizuálu. V řádku souhrnů Celkem již na funkci SUM() nepůsobí žádné filtry, a výsledek měřítka [Prodeje] v řádku souhrnů odpovídá opět součtu všech hodnot ze sloupce 'Sales'[Sales Amount]. Obdobným způsobem by na funkci SUM() působily také filtry z jiných vizuálů na aktuální stránce v reportu, například z Průřezů a podobně.

Shrnutí

Při používání agregačních funkcí musíme vždy přemýšlet o tom, v jakém kontextu bude vybraná funkce vyhodnocena. Všechny agregační funkce totiž ignorují kontext řádku, ale respektují kontext filtru. V pokročilejších výpočtech je pak zcela běžné že v určité části výpočtu působí na konkrétní funkci jeden nebo více filtrů a jeden nebo více kontextů řádků současně. V těchto případech již vyžaduje pochopení chování jednotlivých funkcí určitou praxi. Relativně často také nastává situace, kdy potřebujeme v určité části výpočtu změnit kontext řádku na kontext filtru. K tomuto účelu pak můžeme použít funkci CALCULATE(), jak je popsáno v samostatném příspěvku.

č. 12

Komentáře