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ů
Kapitola 4

Oblasti použití jazyka DAX

Poznejte čtyři hlavní způsoby aplikace DAX v Power BI: sloupce, míry, tabulky a visual calcs
⏱️ Přibližně 100 minut 🎯 Praktické aplikace 📊 Pokročilé techniky

Co se naučíte

  • Počítané sloupce: RELATED(), LOOKUPVALUE(), kdy je používat vs Power Query
  • Měřítka: Agregace v kontextu filtru, base vs compound measures
  • Počítané tabulky: CALENDAR(), SUMMARIZE(), DISTINCT()
  • Visual Calculations (nové v 2024): Když měřítka nestačí
  • Rozhodování: Sloupec nebo míra? Tabulka nebo query?
4.1

Počítané sloupce (Calculated Columns)

Počítaný sloupec se vyhodnocuje řádek po řádku a uloží se v modelu. Je součástí tabulky jako normální sloupec.

Základní syntax a Use cases — reálné příklady z AdventureWorks

DAX
-- Případ 1: Aritmetický výpočet z hodnot řádku
-- FactInternetSales[Margin detail]
FactInternetSales[SalesAmount] - FactInternetSales[TotalProductCost]

-- Případ 2: Concatenace — složený klíč pro párování
-- FactInternetSales[record_key]
FactInternetSales[CurrencyKey] & "_" & FactInternetSales[OrderDateKey]

-- Případ 3: RELATED — přes přímou relaci
-- DimProduct[Sorter] — Sorter z tabulky Category Group
RELATED('Category Group'[Sort])

-- Případ 4: RELATED + VAR + podmínka
-- DimProduct[Category]
VAR _rel = RELATED(DimProductCategory[EnglishProductCategoryName])
RETURN IF(_rel = BLANK(), "Other", _rel)
DAX
-- Případ 5: LOOKUPVALUE bez přímé relace (1 kritérium)
-- DimProduct[Subcategory]
LOOKUPVALUE(
    DimProductSubcategory[EnglishProductSubcategoryName]  -- co chci vrátit
    ,DimProductSubcategory[ProductSubcategoryKey]          -- skenovaný sloupec
    ,DimProduct[ProductSubcategoryKey]                    -- hledaná hodnota pro shodu
)

-- Případ 6: LOOKUPVALUE se dvěma kritérii (kurz měny + datum)
-- FactInternetSales[Sales Original]
LOOKUPVALUE(
    FactCurrencyRate[EndOfDayRate]  -- co hledám
    ,FactCurrencyRate[Date]          -- skenovaný sloupec 1
    ,FactInternetSales[OrderDate]   -- hledaná hodnota 1
    ,FactCurrencyRate[CurrencyKey]  -- skenovaný sloupec 2
    ,FactInternetSales[CurrencyKey]  -- hledaná hodnota 2
) * FactInternetSales[SalesAmount]

RELATED() vs LOOKUPVALUE()

Funkce Kdy se používá Výhody Omezení
RELATED() Existuje přímá relace 1:N Jednoduché, snadný audit relací Potřebuje relaci; řešení méně flexibilní
LOOKUPVALUE() Složité lookup bez přímé relace Flexibilní, může mít více kritérií Pomalejší, méně čitelné

Kdy použít Calculated Column vs Power Query

Scenario Calculated Column Power Query
Transformace jednoho sloupce ✓ Rychlejší vývoj ✓ Snižuje model size
Kategorizace, bucket ✓ Dynamické se filtr contextom ✓ Předvypočítáno, bez refresh nutnosti
Lookup z jiné tabulky ✓ Jednoduché, ale paměť-náročné ✓ Merge, lepší pro velké sady
⚠️
Performance tip: Každý počítaný sloupec zvětšuje model (v import modu). Používejte je spárně. Pro výpočty na řádky během reportingu, zvažte místo toho visual-level DAX.
4.2

Měřítka (Measures)

Míra je vyhodnocena v kontextu filtru (slicing/dicing) a nevede se do modelu. Optimální pro agregace.

Base Measures — reálné míry z kurzu

Základní míra (base measure) provádí jednoduchou agregaci a slouží jako stavební blok pro složitější výpočty.

DAX
-- Internet prodeje (internetový kanál)
# Internet = SUM(FactInternetSales[SalesAmount])

-- Reseller prodeje (distribuční kanál)
# Reseller = SUM(FactResellerSales[SalesAmount])

Compound Measures — složené míry s podmíněnou logikou

DAX
-- Cíl (Target): BLANK na úrovni měsíce, jinak suma
-- HASONEVALUE = TRUE, pokud je vybrán právě jeden měsíc
# TGT =
IF(
    HASONEVALUE('DimDate'[MonthNumberOfYear])
    ,BLANK()
    ,SUM('FactSalesQuota'[SalesAmountQuota])
)

-- Variance vs Target: BLANK pokud chybí TGT nebo Reseller
# VTGT =
IF(
    ISBLANK([# TGT]) || ISBLANK([# Reseller])
    , BLANK()
    , [# Reseller] - [# TGT]
)

-- Splnění plánu v %: DIVIDE pro bezpečné dělení
% TGT =
DIVIDE(
    [# Reseller]
    ,[# TGT]
)
💡
Konvence pojmenování: V kurzu používáme prefix # pro absolutní hodnoty a % pro procenta. To pomáhá seskupovat míry a usnadňuje orientaci v Field Listu.

Implicit vs Explicit Measures

Implicit (Default): Power BI automaticky vytvoří agregaci (SUM, AVERAGE, ...) když přetáhnete sloupec do measure placeholde.

Explicit (Doporučeno): Vy explicitně definujete míru v Field listu. Lépe se audituje a řídí.

✓
Best practice: Vždy vytvářejte Explicit measures. Implicit measures vedou k matoucímu kodu a obtížím při údržbě.
4.3

Počítané tabulky (Calculated Tables)

Počítaná tabulka je tabulka vytvořená pomocí DAX výrazu a uložená v modelu. Existují dvě hlavní použití: data a reference.

CALENDAR() pro date tabulku — reálný příklad z kurzu

Tabulka Kalendar v kurzu je vytvořena jako calculated table s dynamickým rozsahem 4 let a pak rozšířena o počítané sloupce.

DAX
-- Základ tabulky: 4 roky dynamicky od dnešního roku
-- Tabulka Kalendar
VAR _cy = YEAR(TODAY())
VAR _ly = _cy - 1
RETURN
    CALENDAR(
        DATE(_cy-2, 1, 1)
        ,DATE(_cy+1, 12, 31)
    )

Počítané sloupce v date tabulce

DAX
-- Rok, Kvartál, Měsíc
Rok         = YEAR('Kalendar'[Date])
Kvartal     = QUARTER('Kalendar'[Date])
Mesic       = MONTH('Kalendar'[Date])

-- Lokalizovaný název měsíce (česky)
'Mesic nazev' = FORMAT('Kalendar'[Date], "MMMM", "cs-cz")

-- Příznak víkendu: WEEKDAY(...,2) vrací 1=Po...7=Ne
'Je Vikend' = WEEKDAY('Kalendar'[Date], 2) > 5

-- Integer klíč pro snapshot / párování: YYYYMMDD
'Datum Int' =
    'Kalendar'[Rok] * 10000 +
    'Kalendar'[Mesic] * 100 +
    DAY('Kalendar'[Date])

-- Relativní rok vůči dnešku (0 = letos, -1 = loni)
'Relativni rok' = DATEDIFF(TODAY(), 'Kalendar'[Date], YEAR)

-- Státní svátek: LOOKUPVALUE ze samostatné tabulky svatky
-- Vrátí název svátku, pokud datum v Kalendar odpovídá datu v tabulce svatky
Svatek =
    NOT(ISBLANK(
        LOOKUPVALUE(
            'svatky'[Svatek]   -- co vrátit: název svátku
            ,'svatky'[Date]    -- skenovaný sloupec: datum v tabulce svatky
            ,'Kalendar'[Date]  -- hledaná hodnota: datum z Kalendar
        )
    ))

SUMMARIZE() + ADDCOLUMNS() pro referenční tabulky

DAX — Tabular Editor (TABLE keyword je TMDL syntaxe; v Power BI Desktop použijte New Table)
-- DOPORUČENÝ vzor: ADDCOLUMNS + SUMMARIZE (ne výpočty přímo v SUMMARIZE)
-- Agregace přímo v SUMMARIZE() jsou anti-pattern — mohou vrátit nesprávné výsledky
TABLE ProductSummary =
  ADDCOLUMNS(
    SUMMARIZE(
      Sales,
      Product[ProductKey],
      Product[ProductName],
      Product[Category]
    ),
    "TotalSales", SUM(Sales[Amount])  -- výpočet mimo SUMMARIZE
  )

-- DISTINCT: unique hodnoty jednoho sloupce
TABLE UniqueCities =
  DISTINCT(Customer[City])

Jiné operace s tabulkami

Funkce Popis Příklad
UNION() Kombinuj řádky dvou tabulek UNION(Table1, Table2)
EXCEPT() Řádky z Table1 mimo Table2 EXCEPT(Table1, Table2)
INTERSECT() Běžné řádky obou tabulek INTERSECT(Table1, Table2)
CROSSJOIN() Kartézský součin CROSSJOIN(Table1, Table2)
⚠️
Vývoj: Computed Tables se vyhodnocují při refresh modelu. Pokud jsou těžké, refresh může trvat dlouho. Testujte ve vývoji!
4.4

Visual Calculations NEW 2024

Visual Calculations se vyhodnocují uvnitř vizuálu, nikoliv v modelu. Vidí data tak, jak jsou uspořádána na ose X nebo v řádcích matice — bez nutnosti CALCULATE, EARLIER ani složitého filter contextu.

ℹ️
Klíčový rozdíl od míry: Míra neví, která data jsou "předchozí" nebo "vedle". Visual Calculation to ví, protože operuje nad seřazenou sadou výsledků vizuálu — podobně jako window funkce v SQL.

Přehled nejdůležitějších funkcí

FunkcePopisTypické použití
PREVIOUS()Hodnota předchozího řádkuSrovnání inventáře den/den
NEXT()Hodnota následujícího řádkuForecast vs actual
RUNNINGSUM()Kumulativní součetYTD bez DATESYTD
MOVINGAVERAGE(N)Klouzavý průměr N řádkůVyhlazení trendu
RANK()Pořadí v rámci vizuáluTop N produkty
INDEX(N)N-tý řádek (absolutní)Benchmark: první měsíc = 100 %

Reálný příklad z kurzu — inventář den po dni

Tabulka zobrazuje stav skladu (# Inventory Balance USD) po dnech. Visual Calculations přidávají srovnání s předchozím dnem a barevný indikátor — bez jediné změny v modelu:

DAX — Visual Calculation
-- "Versus previous": Denní změna hodnoty inventáře
-- Definuje se přímo v tabulkovém vizuálu (ne v modelu!)
IF(ISBLANK(PREVIOUS([# Inventory Balance USD])), BLANK(),
    [# Inventory Balance USD] -
    PREVIOUS([# Inventory Balance USD])
)

-- "Barva": Podmíněné formátování přes odvozenou Visual Calculation
-- Sloupec Barva je hidden, použit jen jako podmínka formátu
IF([Versus previous] < 0, "Red", "Green")
💡
Proč ne míra? Míra # Balance vs Previous by vyžadovala CALCULATE + DATEADD + FILTER na FactProductInventory — a stále by nevěděla, co je "předchozí řádek" v tabulce. PREVIOUS() to ví vždy, protože pracuje nad výsledkem vizuálu.

Další příklady — prodeje po měsících

DAX — Visual Calculation
-- Kumulativní Internet prodeje (YTD bez DATESYTD)
RUNNINGSUM([# Internet])

-- MoM Growth % — měsíc/měsíc
DIVIDE(
    [# Internet] - PREVIOUS([# Internet]),
    PREVIOUS([# Internet])
)

-- Rank produktů podle # Internet (sestupně)
RANK(DENSE, [# Internet], DESC)

-- Klouzavý průměr 3 měsíce
MOVINGAVERAGE([# Internet], 3)
4.5

Porovnání: Sloupec vs Míra vs Tabulka

Vlastnost Calculated Column Measure Calculated Table
Vyhodnocení Řádek po řádku (row context) V kontextu filtru (filter context) Při refresh modelu
Uložení v modelu Ano, zvětšuje model Ne, dynamic Ano, zvětšuje model
Kdy se počítá Při refresh modelu Na požádání (ad-hoc) Při refresh modelu
Použití v sliceru Ano, jako normální sloupec Ne (není sloupec) Ano, jako normální tabulka
Výkon Velmi rychlé (precomputed) Závisí na query, optimální pro web Závisí na complexity (refresh speed)
Případ použití Transformace, kategorizace, lookup Agregace, poměry, YoY growth Date tabulka, reference lookup
💡
Rozhodovací strom: Potřebuji hodnotu v každém řádku tabulky? → Sloupec. Chci agregovat na základě filtrů v reportu? → Míra. Chci referenční data (kalendář, lookup)? → Tabulka.