GOC644 — DAX základy (2 dny)
1. Úvod do Power BI 2. Datový model 3. Úvod do DAX 4. Oblasti použití DAX 5. Kontext výpočtu 6. Časová inteligence 7. Optimalizace DAX 8. Row Level Security 9. Nástroje
GOC6441 — Pokročilý DAX (2 dny)
1. Opakování & přehled 2. Dynamické reporty 3. DAX jako dotazovací jazyk 4. VertiPaq engine 5. Ladění výkonu 6. Composite Models 7. Workshop
Cvičení
1. Datový model 2. DAX základy 3. Kontext výpočtu 4. Časová inteligence
🏠 Rozcestník kurzů
GOC644 · Kapitola 5

Kontext výpočtu

Pochopení řádkového a filtrového kontextu — páteř Power BI a DAX
⏱ 45 minut🗂 Kapitola 5

Cíle kapitoly

  • Pochopit rozdíl mezi řádkovým a filtrovým kontextem
  • Naučit se jak CALCULATE konvertuje kontexty
  • Ovládat funkce ALL, ALLSELECTED a ALLEXCEPT
  • Pracovat s iterátory (SUMX, MAXX, AVERAGEX)
  • Optimalizovat kód pomocí proměnných (VAR...RETURN)
5.1

Úvod do kontextu

Kontext je jedním z nejdůležitějších konceptů v DAX a Power BI. Představuje "prostředí", v kterém se výpočet provádí. Bez pochopení kontextu je nemožné psát korektní a efektivní DAX kód.

V Power BI existují dva hlavní typy kontextu:

  • Řádkový kontext – vztahuje se na konkrétní řádek v tabulce, typický pro vypočítané sloupce
  • Filtrový kontext – určuje, které řádky jsou zahrnuty v agregaci, typický pro míry
ℹ️
Kontext je dynamický a mění se na základě filtru v Power BI vizuálu. Stejný kód DAX může dávat různé výsledky v závislosti na kontextu.
5.2

Řádkový kontext (Row Context)

Řádkový kontext existuje, když pracujeme s konkrétním řádkem v tabulce. Nejčastěji se vyskytuje v vypočítaných sloupcích a v iterátor funkcích.

Kdy existuje řádkový kontext?

  • Při vytváření vypočítaného sloupce v tabulce
  • Uvnitř funkcí SUMX, MAXX, MINX, AVERAGEX
  • V RLS filtrech (Row Level Security)
  • Funkce RELATED() pracuje s řádkovým kontextem

Příklad: Vypočítaný sloupec

V tabulce FactInternetSales chceme vytvořit sloupec "Celková cena":

DAX
TotalPrice = OrderQuantity * UnitPrice

Když DAX vyhodnocuje tento výraz, má přístup k hodnotám aktuálního řádku (OrderQuantity a UnitPrice). To je řádkový kontext.

RELATED() funkce

Řádkový kontext umožňuje používat funkci RELATED() pro přístup k datům z propojené tabulky:

DAX
ProductCategory = RELATED(DimProduct[Category])
⚠️
RELATED() funguje pouze v řádkovém kontextu. V míře (bez explicitního řádkového kontextu iterátoru) vytvoří chybu.
5.3

Filtrový kontext (Filter Context)

Filtrový kontext určuje, které řádky jsou zahrnuty v agregaci. Uplatňuje se na úrovni měr a je určen:

  • Filtry v Power BI vizuálu (slicers, filters)
  • Sloupci na řádcích a sloupcích v kontingenční tabulce
  • Vztahy (relationships) v datovém modelu

Příklad: Měra s filtrovým kontextem

Definujeme měru "Total Sales":

DAX
Total Sales = SUM(FactInternetSales[SalesAmount])

Pokud je vizuál filtrován na rok 2020 a kategorii "Bikes", měra se automaticky vypočítá pouze pro řádky odpovídající těmto filtrům. To je filtrový kontext.

Jak filtrový kontext funguje

Power BI aplikuje filtrový kontext automaticky:

  1. Uživatel vybere v sliceru hodnotu (např. rok 2020)
  2. DAX vytvoří filtr: [Year] = 2020
  3. Agregace (SUM) se provede pouze na řádcích splňujících filtr
Aspekt Řádkový kontext Filtrový kontext
Kde se používá Vypočítané sloupce, iterátor funkce Míry, vizuály
Jak pracuje Iteruje přes řádky v tabulce Filtruje řádky na základě výběru
Funkce RELATED Funguje ✓ Nefunguje ✗
LOOKUPVALUE Funguje ✓ Funguje ✓
5.4

Konverze kontextu (Context Transition)

Konverze kontextu je proces, kdy se řádkový kontext převede na filtrový kontext. To je klíč k pochopení funkce CALCULATE.

Jak funguje konverze

Když se měra vyhodnocuje v řádkovém kontextu (např. v iterátoru SUMX), DAX automaticky převede příslušné sloupce na filtry v filtrovém kontextu. Například:

DAX
-- ❌ ŠPATNĚ: SUM() inline nevyvolá context transition
-- FactInternetSales zůstane nefiltrovaný — výsledek je Grand Total × řádků
Total by Product WRONG =
SUMX(DimProduct, SUM(FactInternetSales[SalesAmount]))

-- ✓ SPRÁVNĚ varianta 1: volejte míru (míra spustí context transition)
Total by Product =
SUMX(DimProduct, [# Internet])

-- ✓ SPRÁVNĚ varianta 2: explicitní CALCULATE
Total by Product v2 =
SUMX(DimProduct, CALCULATE(SUM(FactInternetSales[SalesAmount])))

Context transition nastane pouze tehdy, když iterátor volá míru nebo výraz obalený v CALCULATE. Inline volání SUM(Table[Col]) uvnitř SUMX context transition nespustí — FactInternetSales zůstane nefiltrovaný a výsledek bude nesprávný (Grand Total opakovaný pro každý řádek DimProduct).

Volání míry v iterátoru spouští context transition

Míru lze zjednodušeně chápat jako výraz vyhodnocený v prostředí podobném CALCULATE — proto volání míry uvnitř SUMX/AVERAGEX spustí context transition. Důležité: toto platí pro volání míry, nikoli pro inline výrazy jako SUM():

DAX
-- Vaše definice měry:
Total Sales = SUM(FactInternetSales[SalesAmount])

-- Ekvivalent v Power BI:
Total Sales = CALCULATE(
  SUM(FactInternetSales[SalesAmount]),
  -- konverze řádkového kontextu na filtrový
)
💡
Toto vysvětluje, proč se míry chují jinak než vypočítané sloupce. Míry pracují v filtrovém kontextu, vypočítané sloupce v řádkovém.
5.5

Funkce CALCULATE — Hlubší pohled

CALCULATE je nejdůležitější funkce v DAX pro ovládání filtru. Umožňuje přidávat, přepisovat a odstraňovat filtry v kontextu.

Syntaxe

DAX
CALCULATE(
  expression,
  filter1, filter2, ..., filterN
)

Příklad: Filtr přes IN — přímý argument CALCULATE

Nejjednodušší forma filtru — predikát přímo jako argument. Power BI interně převede na list hodnot:

DAX
-- Prodeje jen pro vybrané barvy (Blue, Red, Black)
-- Přímý argument CALCULATE — rychlejší než FILTER
# Internet Colors =
CALCULATE(
    [# Internet]
    ,'DimProduct'[Color] IN {"Blue", "Red", "Black"}
)

Příklad: Stejný výsledek přes FILTER()

FILTER() iteruje celou tabulku — pomalejší, ale nutné pro komplexní podmínky (FIND, NOT, vnořené funkce):

DAX
-- Stejný výsledek jako # Internet Colors, ale přes FILTER
# Internet Color Filters =
CALCULATE(
    [# Internet]
    ,FILTER(
        DimProduct,
        'DimProduct'[Color] IN {"Blue", "Red", "Black"}
    )
)

-- FIND: hledej slovo v textu — nutné použít FILTER
-- 4. argument (notFoundValue = 0) zajistí, že FIND() nevrátí chybu
# Internet Like =
CALCULATE(
    [# Internet]
    ,FILTER('DimProduct'
    ,FIND("bike", 'DimProduct'[ModelName], 1, 0) > 0
    )
)
💡
Přímý filtr vs FILTER(): Pokud podmínka je jednoduchý predikát na jednom sloupci jedné tabulky, použijte přímý argument (DimProduct[Color] IN {...}). FILTER() je nutný jen pro složené podmínky přes více sloupců nebo funkce jako FIND, SEARCH, NOT(ISBLANK(...)).

Jak fungují filtry v CALCULATE

  • Sloupec = Hodnota – ADD: přidá filtr (v kombinaci s ostatními filtry)
  • ALL(tabulka) – OVERRIDE: odstraní všechny filtry na tabulce
  • ALLEXCEPT(tabulka, sloupec) – OVERRIDE: odstraní všechny filtry kromě jednoho sloupce
  • FILTER(tabulka, podmínka) – ADD: přidá komplexní filtr

Příklad: CALCULATE + ALL — Bikes přes všechny sortery

ALL() odstraní filtr na sloupci Sorter, aby se Bikes počítalo bez ohledu na řazení:

DAX
-- Prodeje Bikes — ignoruj sloupec Sorter
# Internet Bikes =
CALCULATE(
    [# Internet]
    ,DimProduct[Category] = "Bikes"
    ,ALL('DimProduct'[Sorter])
)
⚠️
CALCULATE kombinuje filtry logikou AND. Filtry na různých sloupcích se násobí (průnik). Filtry na stejném sloupci také tvoří průnik — CALCULATE([m], T[Color]="Blue", T[Color]="Red") vrátí prázdno, ne výsledek pro Red. Chování "přepíše" platí jen pro OVERRIDE funkce (ALL, REMOVEFILTERS).
5.6

Funkce pro filtrování

ALL() — odstraní filtr ze sloupce

Odstraní filtr na konkrétním sloupci — umožňuje vypočítat „celkový internet" bez ohledu na aktuálně vybranou barvu:

DAX
-- Prodeje přes všechny barvy (ignoruj slicer/filtr na Color)
# Internet ALL =
CALCULATE(
    [# Internet]
    ,ALL(DimProduct[Color])
)

ALLSELECTED() — zachová výběr ze sliceru

Odstraní filtry z vizuálu (řádky tabulky), ale zachová výběr ze slicerů — vhodné pro „podíl ze sliceru":

DAX
-- Celkové prodeje v rámci vybraných barev (ze sliceru)
-- Na rozdíl od ALL(), respektuje výběr uživatele
# Internet ALLSELECTED =
CALCULATE(
    [# Internet]
    ,ALLSELECTED(DimProduct[Color])
)
ℹ️
ALL vs ALLSELECTED: Mějte v matici barvy jako řádky a ve sliceru vyberte Blue+Red. Pak:
# Internet ALL = součet VŠECH barev
# Internet ALLSELECTED = součet jen Blue+Red (výběr ze sliceru)

ALLEXCEPT() — odstraní vše kromě

DAX
-- Odstraní VŠECHNY filtry z DimProduct KROMĚ filtru na Color
-- Výsledek: součet Reseller pro celou kategorii bez ohledu na ostatní filtry DimProduct
# Reseller ALLEXCEPT Color =
CALCULATE(
    [# Reseller],
    ALLEXCEPT('DimProduct', 'DimProduct'[Color])
)

USERELATIONSHIP — aktivace neaktivní relace

FactInternetSales má tři relace na DimDate (OrderDate, DueDate, ShipDate). Výchozí je DueDate. Pro filtr přes OrderDate aktivujeme neaktivní relaci:

DAX
-- Internet prodeje filtrované podle data objednávky (ne due date)
# Internet USERELATIONSHIP =
CALCULATE([# Internet]
    ,USERELATIONSHIP(
        'DimDate'[DateKey],
        FactInternetSales[OrderDateKey]
    )
)

TREATAS — virtuální relace

TREATAS "přikládá" sloupce tabulky jako filtr na jiné sloupce. Použití: Reseller filtrovaný přes DueDate z Internet prodejů:

DAX
-- Reseller prodeje filtrované přes DueDate z Internet faktury
# Reseller TREATAS =
CALCULATE(
    [# Reseller]
    ,TREATAS(
        DISTINCT('FactInternetSales'[DueDateKey])
        ,FactResellerSales[DueDateKey]
    )
)
5.7

Iterátor funkce

Iterátor funkce projdou tabulkou řádek po řádku a vyhodnotí výraz pro každý řádek. Vytváří řádkový kontext.

SUMX — Součet s iterací

Součet výrazů vypočítaných pro každý řádek. Nutné pro výpočty jako „cena × množství" nebo pro práci se snímky inventáře:

DAX
-- Hodnota inventáře k poslednímu dni (snapshot)
-- Nejdříve najdeme MAX datum přes všechny produkty,
-- pak SUMX spočítá cena * množství pro každý řádek
# Inventory Balance USD =
VAR _md = CALCULATE(MAX(FactProductInventory[DateKey]), ALL('DimProduct'))
VAR _rslt =
    CALCULATE(
        SUMX(
        'FactProductInventory'
        ,'FactProductInventory'[UnitCost] * 'FactProductInventory'[UnitsBalance]
        ),
        FactProductInventory[DateKey] = _md
    )
RETURN _rslt
💡
Proč VAR + CALCULATE? Proměnná _md zachytí maximální datum bez filtru (ALL). Pak CALCULATE filtruje FactProductInventory na tento jeden den a SUMX projede řádky a spočítá hodnotu inventáře.

MAXX, MINX, AVERAGEX

Podobně jako SUMX, ale pro maximum, minimum a průměr:

DAX
-- Průměrná prodejní hodnota na transakci (Qty * UnitPrice per row)
AVERAGEX(
  FactInternetSales,
  FactInternetSales[OrderQuantity] * FactInternetSales[UnitPrice]
)

SUM vs SUMX

Klasický SUM je vlastně zjednodušené SUMX bez iterace:

DAX
-- Toto jsou ekvivalenty:
SUM(FactInternetSales[SalesAmount])

SUMX(
  FactInternetSales,
  SalesAmount
)
⚠️
Iterátor funkce jsou pomalejší než agregace (SUM, COUNT). Používejte je pouze když potřebujete iteraci na konkrétní výraz.
5.8

Proměnné a VAR...RETURN

Proměnné zlepšují čitelnost kódu a mohou zlepšit výkon. Proměnná zaznamenává aktuální kontext v místě deklarace.

Syntaxe VAR...RETURN

DAX
VAR MyVariable = /* výraz */
RETURN /* výraz používající MyVariable */

Příklad: Měra s proměnnými

DAX
Percentage of Total Sales =
VAR CurrentSales = SUM(FactInternetSales[SalesAmount])
VAR TotalSales = CALCULATE(
  SUM(FactInternetSales[SalesAmount]),
  REMOVEFILTERS(DimProduct, DimCustomer)  -- ALL() bere 1 tabulku nebo n sloupců; REMOVEFILTERS pro více tabulek
)
RETURN DIVIDE(CurrentSales, TotalSales)

Proč používat proměnné?

  • Čitelnost: Jméno proměnné vysvětluje, co se počítá
  • Údržba: Snadnější změna kódu (modifikujete jeden výraz)
  • Výkon: Výraz se vyhodnotí pouze jednou a znovu se používá
  • Debugging: Snadnější identifikovat problém v komplexních vzorcích

Příklad: Komplexní měra s více proměnnými

DAX
Revenue Analysis =
VAR CurrentYear = MAX(DimDate[Year])
VAR CurrentRevenue = SUM(FactInternetSales[SalesAmount])
VAR PreviousRevenue = CALCULATE(
  SUM(FactInternetSales[SalesAmount]),
  DimDate[Year] = CurrentYear - 1
)
VAR Growth = DIVIDE(
  CurrentRevenue - PreviousRevenue,
  PreviousRevenue
)
RETURN Growth
✓
Proměnné zaznamenávají kontext v místě deklarace. To znamená, že pokud deklarujete proměnnou s filtrů, ta hodnota se "zmrazí" pro budoucí operace.