Příklady použití DAX funkce KEEPFILTERS

Příklady použití DAX funkce KEEPFILTERS

Funkce KEEPFILTERS() se používá k úpravě chování filtrů ve funkci CALCULATE(). Pokud použijeme funkci KEEPFILTERS(), tak funkce CALCULATE() nebude přepisovat vnější filtry, ale vyhodnotí explicitní filtry definované uvnitř CALCULATE() v průniku s vnějšími filtry. V tomto příspěvku si ukážeme příklady použití DAX funkce KEEPFILTERS() v Power BI.

K tomuto tématu je k dispozici také video.

Začít můžeme přípravou vizuálu se kterým budeme pracovat. V použitém cvičném Power BI souboru, který je k dispozici ke stažení níže pod tímto příspěvkem, si do vizuálu matice vložíme kategorie produktů a měřítko [Prodeje], které má následující definici.

Měřítko:

Prodeje = SUM(Sales[Sales Amount])

Výchozí jednoduchý Power BI vizuál, se kterým budeme pracovat, může vypadat například následovně.

Příklady použití DAX funkce KEEPFILTERS 2

Uvažujme nyní následující dvě měřítka. Obě měřítka budou vracet prodeje za produkty v kategorii Bikes, nicméně filtry ve funkci CALCULATE() budou v každém měřítku fungovat jiným způsobem.

Měřítko [Prodeje (Bikes)] bude přepisovat vnější filtry nastavené na sloupec 'Product'[Category].

Měřítko:

Prodeje (Bikes) =
CALCULATE
(
    [Prodeje],
    'Product'[Category] = "Bikes"
)

Měřítko [Prodeje (Bikes) KeepFilters] vyhodnotí filtr definovaný ve funkci CALCULATE() v průniku s vnějšími filtry nastavenými na sloupec 'Product'[Category], a to právě díky funkci KEEPFILTERS().

Měřítko:

Prodeje (Bikes) KeepFilters =
CALCULATE
(
    [Prodeje],
    KEEPFILTERS('Product'[Category] = "Bikes")
)

Pokud obě nová měřítka vložíme do původního vizuálu, budeme moci na první pohled vidět efekt použití funkce KEEPFILTERS().

Příklady použití DAX funkce KEEPFILTERS 3

Filtr v měřítku [Prodeje (Bikes)] nastavený na sloupec 'Product'[Category] a na hodnotu Bikes přepisuje vnější filtry z tohoto sloupce, tzn. přepisuje filtry, které působí na výpočet z řádků vizuálu. Měřítko [Prodeje (Bikes)] proto vrací v každém řádku sumu za prodeje produktů v kategorii Bikes, bez ohledu na to v jakém řádku vizuálu se nacházíme.

Funkce KEEPFILTERS() pak zajistí, že vnější filtry budou zachovány, a měřítko [Prodeje (Bikes) KeepFilters] vrací prodeje za produkty v kategorii Bikes pouze v případě, kdy se vnější filtry nastavené na sloupec 'Product'[Category] nevylučují s filtrem definovaným uvnitř funkce KEEPFILTERS()

Pokud se zaměříme na druhý řádek vizuálu, tak v tomto řádku působí na měřítka filtr nastavený na kategorii Bikes. Filtr v měřítku '[Prodeje (Bikes) KeepFilters] je nastavený také na kategorii Bikes. To znamená, že tyto filtry se navzájem nevylučují, a výsledkem jsou prodeje v dané kategorii. 

Ve třetím řádku vizuálu je vnější filtr nastaven na kategorii Clothing. Filtr nastavený na stejný sloupec v měřítku [Prodeje (Bikes) KeepFilters] je nastavený na hodnotu Bikes. Tyto dva filtry se navzájem vylučují a měřítko [Prodeje (Bikes) KeepFilters] proto vrací ve třetím řádku vizuálu prázdnou hodnotu BLANK.

V řádku souhrnů nepůsobí na výpočet v měřítku [Prodeje (Bikes) KeepFilters] žádný vnější filtr ze sloupce 'Product'[Category]. Výsledný filtr tak obsahuje pouze hodnotu Bikes a měřítko [Prodeje (Bikes) KeepFilters] vrací v řádku souhrnů opět prodeje za produkty v této kategorii.

Na základě výše uvedených rozdílů mezi filtry ve funkci CALCULATE() bez použití funkce KEEPFILTERS() a s použitím funkce KEEPFILTERS() by mělo být zřejmé, že ve výchozím nastavení filtry definované ve funkci CALCULATE() přepisují vnější filtry nastavené na stejné sloupce, a filtry vložené do funkce KEEPFILTERS() jsou vyhodnoceny v průniku s vnějšími filtry.

Tento první příklad je typickým příkladem pro vysvětlení chování funkce KEEPFILTERS(), nicméně v této konkrétní situaci se obvykle funkce KEEPFILTERS() nepoužívá. Pokud totiž v měřítku filtrujeme jeden sloupec na jednu konkrétní hodnotu, obvykle chceme opravdu přepsat případné vnější filtry z tohoto sloupce novým filtrem.

Uvažujme například následující dvě měřítka, která budou vracet procentuální podíl aktuálních prodejů vůči prodejům v kategorii Bikes.

V měřítku [% Podíl vůči Bikes] použijeme v děliteli výpočet bez použití funkce KEEPFILTERS().

Měřítko:

% Podíl vůči Bikes =
IF
(
    HASONEVALUE('Product'[Category]),
    DIVIDE
    (
        [Prodeje],
        CALCULATE
        (
            [Prodeje],
            'Product'[Category] = "Bikes"
        )
    )
)

V dalším měřítku pak bude v děliteli výpočet s použitím funkce KEEPFILTERS().

Měřítko:

% Podíl vůči Bikes (špatně) =
IF
(
    HASONEVALUE('Product'[Category]),
    DIVIDE
    (
        [Prodeje],
        CALCULATE
        (
            [Prodeje],
            KEEPFILTERS('Product'[Category] = "Bikes")
        )
    )
)

Obě nová měřítka si opět vložíme do vizuálu matice s kategoriemi produktů v řádcích.

Příklady použití DAX funkce KEEPFILTERS 4

Jak je zřejmé z výše zobrazeného vizuálu, tak měřítko bez použití funkce KEEPFITLERS() vrací v každém řádku vizuálu procentuální podíl prodejů v aktuální kategorii vůči prodejů v kategorii Bikes. V tomto výpočtu jsme tedy opravdu chtěli v děliteli přepsat vnější filtry a výchozí chování funkce CALCULATE() je vyhovující. 

Na druhou stranu měřítko [% Podíl vůči Bikes (špatně)], ve kterém je v děliteli ve funkci CALCULATE() použita funkce KEEPFILTERS(), vrací hodnotu pouze pro kategorii Bikes, protože v ostatních řádcích obsahuje druhý argument funkce DIVIDE() prázdnou hodnotu BLANK, a to právě díky funkci KEEPFILTERS(), která znemožňuje přepsání vnějších filtrů nastavených na sloupec 'Product'[Category].

Funkce KEEPFILTERS() se většinou používá v situacích, kdy současně filtrujeme ve funkci CALCULATE() více sloupců, a nebo v situacích kdy filtrujeme jeden nebo více sloupců na více hodnot. Tyto typy příkladů si ukážeme v následující části příspěvku.

Kdy používat funkci KEEPFILTERS

Začít můžeme příkladem, ve kterém bude výsledkem filtru ve funkci CALCULATE() více hodnot z jednoho sloupce. V takovéto situaci bychom měli zvážit použití funkce KEEPFILTERS().

Následující dvě měřítka budou vracet prodeje pouze za nákupy, ve kterých se konkrétní produkt prodal v množství menším než 10 kusů.

Měřítko:

Prodeje (Q < 10) =
CALCULATE
(
    [Prodeje],
    Sales[Order Quantity] < 10
)

Výsledný filtr ve funkci CALCULATE() nyní bude obsahovat hodnoty ze sloupce 'Sales'[Order Quantity], které jsou menší než 10. To znamená, že výsledný filtr bude obsahovat hodnoty v rozsahu 1 až 9.

Alternativní měřítko s použitím funkce KEEPFILTERS() bude vypadat následovně.

Měřítko:

Prodeje (Q < 10) KeepFilters =
CALCULATE
(
    [Prodeje],
    KEEPFILTERS(Sales[Order Quantity] < 10)
)

Pokud obě nová měřítka vložíme opět do vizuálu matice s kategoriemi produktů v řádcích, výsledky budou stejné, protože v reportu není žádný vizuál, pomocí kterého bychom filtrovali sloupec 'Sales'[Order Quantity].

Příklady použití DAX funkce KEEPFILTERS 5

Měřítka [Prodeje (Q < 10)] a [Prodeje (Q < 10) KeepFilters] ale budou vracet jiné výsledky, pokud přidáme do reportu průřez, ve kterém budeme také filtrovat množství prodaných kusů, a to například na množství v rozsahu 5 až 10.

Příklady použití DAX funkce KEEPFILTERS 6

Nyní vrací každé měřítko jiné hodnoty. Měřítko [Prodeje] vrací prodeje za produkty prodané v počtu 5 až 10 včetně, tak jak je vybráno v průřezu.

Druhé měřítko, měřítko [Prodeje (Q < 10) KeepFilters] obsahuje uvnitř funkce CALCULATE() filtr nastavený na množství prodaných kusů 1 až 9. Uživatel v průřezu vybral množství 5 až 10. Výsledný filtr, díky funkci KEEPFILTERS(), bude obsahovat průnik těchto dvou filtrů, a proto vidíme v tomto měřítku prodeje za množství 5 až 9. Uživatel se tedy v tomto případě rozhodl ještě více zafiltrovat prodeje, a měřítko [Prodeje (Q < 10) KeepFilters] reaguje na tento dodatečný filtr.

Měřítko [Prodeje (Q < 10)], tzn. měřítko v posledním sloupci vizuálu, přepisuje filtr vybraný v průřezu, protože v tomto měřítku jsme nepoužili funkci KEEPFILTERS(), a výsledkem jsou proto prodeje za produkty prodané v počtech 1 až 9 kusů. Toto měřítko tedy vůbec nereaguje na výběr uživatele v průřezu.

V tomto konkrétním příkladu, kdy filtr ve funkci CALCULATE() obsahuje více hodnot z jednoho sloupce, se tedy obvykle používá funkce KEEPFILTERS(). Jako vždy ale záleží na celkovém významu výpočtu a samozřejmě nejde o žádné psané pravidlo.

Funkci KEEPFILTERS() můžeme použít také pokud současně filtrujeme více sloupců. Následující měřítko bude vracet prodeje za produkty v kategorii Bikes, ale současně pouze za černé a modré produkty.

Měřítko:

Prodeje (Bikes, Blue, Black) =
CALCULATE
(
    [Prodeje],
    KEEPFILTERS
    (
        ('Product'[Category], 'Product'[Color]) IN
        {
            ("Bikes", "Blue"),
            ("Bikes", "Black")
        }
    )
)

Opět i zde, díky použití funkce KEEPFILTERS(), nedojde k přepsání vnějších filtrů nastavených na stejné sloupce, ale k jejich průniku.

Příklady použití DAX funkce KEEPFILTERS 7

Dalším typickým příkladem kdy je funkce KEEPFILTERS() užitečná může být situace, kdy ve výpočtu v prvním kroku potřebujeme získat tabulku se všemi hodnotami z jednoho nebo z více sloupců, a následně tuto tabulku nějakým způsobem zafiltrujeme a použijeme ve filtru funkce CALCULATE().

Uvažujme například měřítko, které bude vracet prodeje pouze pro 10 nejlepších produktů.

Měřítko:

Prodeje (10 nejlepších produktů) špatně =
VAR ProduktyAProdeje =
    ADDCOLUMNS
    (
        ALL('Product'[Product]),
        "@Prodeje",
        [Prodeje]
    )
VAR NejlepsiProdukty =
    TOPN
    (
        10,
        ProduktyAProdeje,
        [@Prodeje],
        DESC
    )
VAR Vypocet =
    CALCULATE
    (
        [Prodeje],
        NejlepsiProdukty
    )
RETURN
    Vypocet

Ve výše uvedeném měřítku je v proměnné ProduktyAProdeje tabulka se všemi produkty a jejich prodeji. Následně z této tabulky pomocí funkce TOPN() vybereme 10 nejlepších produktů podle sumy prodejů. Těchto deset nejlepších produktů uložených v proměnné NejlepsiProdukty je následně použito ve filtru funkce CALCULATE() před vyhodnocením měřítka [Prodeje]

Nové měřítko si vložíme do vizuálu matice, tentokrát s produkty v řádcích. Výsledkem bude suma za prodeje deseti nejlepších produktů v aktuálním kontextu vyhodnocení.

Příklady použití DAX funkce KEEPFILTERS 8

Částka, kterou vrací měřítko [Prodeje (10 nejlepších produktů) špatně] je správná, a odpovídá prodejům za 10 nejlepších produktů, nicméně stejná částka se zobrazuje v každém řádku vizuálu. Pokud tvoříme podobný výpočet, obvykle potřebujeme zobrazit prodeje pro deset nejlepších produktů, ale u každého produktu, který patří mezi deset nejlepších chceme vidět prodeje za tento konkrétní produkt, a v řádu souhrnů prodeje za všech deset nejlepších produktů. Toho můžeme dosáhnout právě pomocí funkce KEEPFILTERS().

V následujícím měřítku je tabulka s deseti nejlepšími produkty vložena do funkce KEEPFILTERS(), cože je jediný rozdíl oproti předchozí variantě výpočtu.

Měřítko:

Prodeje (10 nejlepších produktů) =
VAR ProduktyAProdeje =
    ADDCOLUMNS
    (
        ALL('Product'[Product]),
        "@Prodeje",
        [Prodeje]
    )
VAR NejlepsiProdukty =
    TOPN
    (
        10,
        ProduktyAProdeje,
        [@Prodeje],
        DESC
    )
VAR Vypocet =
    CALCULATE
    (
        [Prodeje],
        KEEPFILTERS(NejlepsiProdukty)
    )
RETURN
    Vypocet

Nové měřítko si opět vložíme do vizuálu matice s produkty v řádcích.

Příklady použití DAX funkce KEEPFILTERS 9

Nová varianta výpočtu vrací prodeje pouze u produktů, které patří mezi 10 nejlepších. V řádku souhrnů pak vidíme součet prodejů za všech 10 nejlepších produktů, což je přesně stejná částka kterou vracelo původní měřítko bez použití funkce KEEPFILTERS() v každém řádku vizuálu.

Pokud odebereme z vizuálu měřítko [Prodeje], uvidíme pouze 10 nejlepších produktů v řádcích vizuálu, díky automatickému filtru, který zneviditelní ty řádky ve vizuálu, pro které vrací všechna měřítka prázdné hodnoty BLANK.

Příklady použití DAX funkce KEEPFILTERS 10

Použití funkce KEEPFILTERS() je jednoduché a intuitivní. Pokud potřebujeme zachovat filtry na sloupcích které současně filtrujeme ve funkci CALCULATE(), použijeme funkci KEEPFILTERS().

Za zmínku ještě stojí dodat, že funkce KEEPFILTERS() není v jazyku DAX k dispozici od prvopočátku a setkat se proto můžeme také s alternativním zápisem výpočtů, které řeší průnik filtrů namísto jejich přepsání jiným způsobem. Zde ale vždy záleží na konkrétním příkladu, protože neexistuje univerzální syntaxe pro nahrazení funkce KEEPFILTERS(). Pro tento účel se často používají funkce VALUES() a SUMMARIZE().

V měřítku [Prodeje (10 nejlepších produktů)] bychom například mohli namísto funkce KEEPFILTERS() přidat do filtru funkce CALCULATE() funkci VALUES() se sloupcem 'Product'[Product] následujícím způsobem.

Měřítko:

Prodeje (10 nejlepších produktů) v2 =
VAR ProduktyAProdeje =
    ADDCOLUMNS
    (
        ALL('Product'[Product]),
        "@Prodeje",
        [Prodeje]
    )
VAR NejlepsiProdukty =
    TOPN
    (
        10,
        ProduktyAProdeje,
        [@Prodeje],
        DESC
    )
VAR Vypocet =
    CALCULATE
    (
        [Prodeje],
        NejlepsiProdukty,
        VALUES('Product'[Product])
    )
RETURN
    Vypocet

Logika výpočtu v proměnné Vypocet je ale jiná než při použití funkce KEEPFILTERS(). Při použití funkce VALUES() nedojde k průniku vnějších filtrů s explicitními filtry ve funkci CALCULATE(), ale k průniku filtrů pouze ve funkci CALUCLATE(). To znamená že funkce VALUES() bude vracet vždy pouze produkty dostupné v aktuálním kontextu vyhodnocení, a pokud se tyto produkty shodují s produkty v tabulce v proměnné NejlepsiProdukty, dojde k průniku těchto dvou filtrů.

Příklady použití DAX funkce KEEPFILTERS 11

Ačkoliv můžeme funkci KEEPFILTERS() ve většině případů nahradit nějakou alternativou, použití funkce KEEPFILTERS() by mělo mít přednost, a to jak z důvodu čitelnosti DAX kódu, tak z důvodu lepší výkonnosti.

Komentáře