Opakování klíčových konceptů
Cíle kapitoly
- Upevnit porozumění reláciím a jejich vlivu na filtrování v DAXu
- Znát rozdíly mezi počítaným sloupcem, measure a počítanou tabulkou
- Pochopit kontexty výpočtu — row context vs. filter context
- Identifikovat a řešit časté chyby z GOC644
- Osvěžit znalost Visual Calculations
Relace a jejich vliv na filtrování
V Power BI jsou relace základem pro automatické filtrování v DAXu. Když je relace aktivní, filtr se automaticky šíří od strany 1 (One) na stranu N (Many). Tento mechanismus ovlivňuje chování RELATED() a FILTER() funkcí.
Jednosměrné a dvousměrné relace
Ve výchozím nastavení jsou relace jednosměrné (One→Many). Výsledkem je, že:
- Filtr ze strany One šíří se na Many: Když je vybrán konkrétní produkt, automaticky se filtrují tržby v tabulce FactInternetSales.
- Opačný směr vyžaduje ruční řešení: Filtrování z Many na One zajistí obousměrná relace, CROSSFILTER() v rámci CALCULATE, nebo TREATAS(VALUES(Fact[Key]), Dim[Key]). Pozor: ALL() filtry odstraňuje — pro propagaci filtru v opačném směru neslouží.
Praktický příklad: Vliv relace na RELATED()
-- RELATED() přistupuje k hodnotám z nadřazené (One) tabulky v row contextu TržbyNadStandardníCenu := SUMX ( FactInternetSales, FactInternetSales[SalesAmount] - RELATED ( DimProduct[StandardCost] ) ) -- RELATED() funguje pouze přes aktivní relace! -- Pokud aktivní relace neexistuje, RELATED() vrátí CHYBU (ne BLANK) -- BLANK vrátí pouze tehdy, když relace existuje, ale pro daný řádek -- neexistuje odpovídající záznam v nadřazené tabulce -- Pozor: RELATED(DimProduct[ProductName]) vrací TEXT — nelze násobit číslem
Ověřte, že existují relace mezi FactInternetSales a DimProduct, DimDate, DimCustomer.
Tržby Prodejce = SUMX(FactResellerSales, FactResellerSales[SalesAmount])
Pak vytvořte druhou: Prodejce Jméno = RELATED(DimSalesTerritory[SalesTerritoryCountry])
Pozorujte, jak se filtrování chová v prostoru sloupce Salesperson.
Počítaný sloupec vs. Measure vs. Počítaná tabulka
Tři různé přístupy k vytváření hodnot v Power BI mají klíčové rozdíly v kontextu vyhodnocení, výkonu a využití.
| Typ | Kontext | Kdy použít | Výkon | Příklad |
|---|---|---|---|---|
| Počítaný sloupec | Row context | Hodnoty, které se mění po řádcích; kategorie | Vyšší paměť (uloženo v modelu) | Profit = Sales - Cost |
| Measure | Filter context | Agregace; dynamické výpočty; náchylné na filtr | Nižší paměť (vypočítáno na dotaz) | Total Sales = SUM(Sales) |
| Počítaná tabulka | Obojí | Kalkulované tabulky pro lookup; agregace na řádcích | Vyšší (tabulka uložena) | TopProducts = TOPN(10, ...) |
Klíčová pravidla
- Počítaný sloupec se vyhodnocuje v row contextu — každý řádek je zpracován jednotlivě. Paměť roste s počtem řádků.
- Measure se vyhodnocuje v filter contextu — reaguje na filtr v tabulce. Vypočítá se až při dotazu.
- Počítaná tabulka je uložená tabulka (jako fyzická tabulka, ale dynamická). Dobrá pro reference, špatná pro paměť.
Visual Calculations — připomenutí
Visual Calculations jsou nová funkce (public preview od března 2024, Power BI Desktop March 2024) umožňující výpočty na úrovni vizualizace, nezávisle na datovém modelu.
Klíčové vlastnosti
- Provádějí se na visuálu, nikoli v datovém modelu (rychlejší, bez paměťové zátěže)
- Pracují s ALLSELECTED() kontextem — mají přístup k datům viditelným ve vizualizaci
- Podtrhují řádky, sloupce, relativní pozice
- Nativně podporují procenta, pořadí, kumulativní součty
-- Kumulativní součet (Running Total) ve Visual Calculations: RUNNINGSUM ( [Total Sales] ) -- Nebo přes WINDOW (explicitní varianta pro složitější řazení): CALCULATE ( [Total Sales], WINDOW ( 1, ABS, 0, REL, ROWS ) )
CALCULATE([Total Sales], ISINSCOPE(DimDate[MonthYear])) je conditional visibility — vypočítá míru jen pokud je MonthYear v scope vizualizace. Kumulativní součet vyžaduje RUNNINGSUM() nebo WINDOW().Row Context vs. Filter Context — hluboké porozumění
Row Context (Kontekt řádku)
Vyskytuje se, když DAX procházení řádky tabulky jednotlivě. Zpravidla v iterátorech (SUMX, FILTERX, atd.) nebo počítaných sloupcích.
- Máte přístup k jednotlivým hodnotám sloupců řádku
- RELATED() pracuje přes relace
- SUM() pracuje v aktuálním filter contextu — nevytváří ho. Context transition nastane pouze při volání míry nebo explicitním CALCULATE() uvnitř iterátoru.
Filter Context (Kontext filtru)
Toto je "prostředí" okolo measure — jaké filtry byly aplikovány z vizualizace, segmentů, apod.
- Určuje, které řádky jsou v rozsahu measure
- CALCULATE() ho ovlivňuje — přidává/odebírá filtry
- Šíří se přes relace (jednosměrně)
Praktická rozdílu — Příklad
TržbyBezFiltrů := SUM ( FactInternetSales[SalesAmount] ) {-- Ovlivněno filter context (filtr z vizualizace) --} TržbyVšechny := CALCULATE ( SUM ( FactInternetSales[SalesAmount] ), ALL ( DimProduct ) ) {-- Odstraňuje filter na DimProduct, ale zachovává ostatní filtry --}
Počítaný sloupec se row contextem
Máte tabulku FactInternetSales. Vytvoříte počítaný sloupec:
ProfitMargin = DIVIDE( RELATED(DimProduct[StandardCost]), [SalesAmount] )
Zde je row context — pro každý řádek se vypočítá marže. RELATED() funguje, protože máme v row contextu přístup k ProductKey.
Measure se filter contextem
TržbyPoProduktové kategorii = SUM(FactInternetSales[SalesAmount])
Když tuto measure vložíte do vizualizace filtrované na kategorii "Bikes", filter context se automaticky aplikuje — measure vrátí jen tržby z Bikes.
Kombinace: SUMX s RELATED a CALCULATE
TržbyZStandardnímiNáklady := SUMX ( FILTER ( FactInternetSales, [SalesAmount] > 100 ), [SalesAmount] + RELATED ( DimProduct[StandardCost] ) )
SUMX vytváří row context (procházíme řádky), FILTER pracuje s filter context (filtruje podle aktuálního contextu), a RELATED přistupuje k třídě přes relaci.
Časté chyby z GOC644 a jejich řešení
Problém: Measure výsledky neodpovídají očekávání, protože filter context není správně smazán.
PercentoZCelkuŠpatně := DIVIDE ( [Tržby], SUM ( FactInternetSales[SalesAmount] ) ) {-- Jmenovatel má stejný filter context jako čitatel! Vždycky vrátí 1.0 (nebo BLANK). --}
PercentoZCeluSpráv := DIVIDE ( [Tržby], CALCULATE ( SUM ( FactInternetSales[SalesAmount] ), ALL ( DimProduct ) ) ) {-- ALL() odstraní filter na DimProduct z filter contextu --}
Problém: Pomalá measure, protože se iteruje bez nutnosti.
TržbyPomalé := SUMX ( FactInternetSales, FactInternetSales[SalesAmount] ) {-- Zbytečná iterace! --}
TržbyRychlé := SUM ( FactInternetSales[SalesAmount] ) {-- Storage Engine si poradí, je to rychlejší --}
Problém: FILTER() s mírou v predikátu způsobuje, že se každý řádek vyhodnocuje ve Formula Engine (pomalé). Filtr se sloupcem je naopak správný vzor — Storage Engine si s ním poradí přímo.
Tržby10Plus := SUMX ( FILTER ( FactInternetSales, FactInternetSales[OrderQuantity] > 10 ), FactInternetSales[SalesAmount] ) -- Sloupec v predikátu = Storage Engine filtr = rychlé
TržbyPomaleFiltr := SUMX ( FILTER ( FactInternetSales, [OrderQtyMeasure] > 10 ), FactInternetSales[SalesAmount] ) -- Míra v predikátu = Formula Engine pro každý řádek = pomalé -- Preferujte CALCULATE([TržbyMíra], FactInternetSales[OrderQuantity] > 10)
Řešení: V predikátu FILTER() používejte sloupce (rychlé, SE pushdown). Pokud filtrujete podle míry, zvažte CALCULATE s podmínkou na sloupci.
Interaktivní shrnutí a kvíz
Která z těchto measures vrátí procento z celkového součtu bez ohledu na filtr?
Odpověď: Measure s CALCULATE(..., ALL(...)), která odstraní filtr v jmenovateli.
DIVIDE([Tržby], CALCULATE([Tržby], ALL(DimProduct)))
Jaký je rozdíl mezi SUMX a SUM v jednoduchém scénáři?
Odpověď: SUM je optimalizovaný Storage Engine, SUMX je iterátor. Pro jednoduchou agregaci bez logiky je SUM vždycky rychlejší.
Kdy SUMX? Když potřebujete logiku v každém řádku (RELATED, DIVIDE, podmínky).
Co je Visual Calculation a kdy se hodí?
Odpověď: Je to výpočet na úrovni vizualizace (ne v modelu). Hodí se pro ranking, running totals, procenta řady — bez paměťové zátěže modelu.