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ů
GOC6441 · Kapitola 2

Tvorba dynamických reportů

Dynamic Measures, Calculation Groups, Field Parameters a pokročilé zabezpečení v Power BI
⏱ 90 minut🔧 Tabular Editor

Cíle kapitoly

  • Vytvářet dynamické metriky s SWITCH
    📝
    Na blogu Jiřího Neorala: Field parameters pro dynamické reporty · Dynamické reporty s výběrem zobrazené metriky — dynamické metriky a filtrace v reportu
    () a Selected Measure patterm
  • Stavět a spravovat Calculation Groups v Tabular Editoru
  • Implementovat Field Parameters pro přepínání metrik a dimenzí
  • Tvořit dynamické časové kalkulace s řízeným posunem
  • Nastavovat Object Level Security (OLS) pro ochranu dat
2.1

Dynamic Measures — SWITCH() a Selected Measure

Dynamic Measures umožňují uživateli vybrat z nabídky metrik a dinamicky měnit, která se zobrazí na vizualizaci.

Tabulka Dynamic — reálný selektor metrik z modelu kurzu

V modelu kurzu máme tabulku Dynamic se dvěma sloupci: ID (číslo) a Metrika (popis). Uživatel si ze sliceru vybere metriku a míra vrátí odpovídající hodnotu.

Dynamic tabulka (statická data)
-- Tabulka Dynamic: ID | Metrika
-- 1 | Internet
-- 2 | Reseller
-- 3 | Internet YTD
-- 4 | Reseller YTD
-- 5 | % Plnění TGT

Varianta 1: Staré řešení — vnořené IF + FORMAT

Původní implementace v kurzu (záměrně ošklivá — demonstruje problém s duplicitním kódem):

DAX — # Dynamicka 1 (duplicitní kód)
-- Podmínka pro formát se opakuje dvakrát!
# Dynamicka 1 =
IF(LEN(
IF(
     MIN('Dynamic'[ID]) = 5,
FORMAT(SWITCH(MIN('Dynamic'[ID]), 1,[# Internet], 2,[# Reseller], 3,[# Internet YTD], 4,[# Reseller YTD], 5,[% TGT]), "0.0%"),
FORMAT(SWITCH(MIN('Dynamic'[ID]), 1,[# Internet], 2,[# Reseller], 3,[# Internet YTD], 4,[# Reseller YTD], 5,[% TGT]), "$#,##0")
)) = 0, BLANK(),
-- ... celý výraz se opakuje ještě jednou ...
)

Varianta 2: Refaktorovaná s VAR

Využití proměnných eliminuje duplikaci — výraz SWITCH se vypočítá jednou:

DAX — # Dynamicka 2 (VAR refactoring)
# Dynamicka 2 =
VAR _sm = MIN('Dynamic'[ID])
VAR _sw =
    SWITCH (
                    _sm,
                    1, [# Internet],
                    2, [# Reseller],
                    3, [# Internet YTD],
                    4, [# Reseller YTD],
                    5, [% TGT]
                )
VAR _swf =
    IF(_sm = 5, FORMAT(_sw, "0.0%"), FORMAT(_sw, "$#,##0"))
VAR _rslt =
    IF(LEN(_swf) = 0, BLANK(), _swf)
RETURN _rslt

Varianta 3: Moderní — SWITCH + formatStringDefinition

Nejčistější přístup (od 2023+): míra vrací číslo, formát je řízen dynamicky přes formatStringDefinition:

DAX — # Dynamicka 3 (doporučená varianta)
-- Míra vrací číslo — žádný FORMAT() uvnitř
# Dynamicka 3 =
     SWITCH(
        MIN('Dynamic'[ID])
        ,1,[# Internet]
        ,2,[# Reseller]
        ,3,[# Internet YTD]
        ,4,[# Reseller YTD]
        ,5,[% TGT]
    )

-- Dynamický formát (nastavuje se zvlášť v TMDL / Tabular Editor):
-- formatStringDefinition = IF(MIN('Dynamic'[ID])=5,"0.0%","$#,##0")
✓
Proč Varianta 3? Vrací skutečné číslo (ne text), takže vizualizace ho může agregovat, podmíněně formátovat a třídit. Varianty 1 a 2 vracely text — nelze je použít v datovém baru nebo minigrafice.
2.2

Calculation Groups — pokročilé agregace

Calculation Groups (CG) jsou mocný mechanismus v Power BI pro aplikaci transformací na measures bez úpravy samotných measures.

Co je Calculation Group?

  • Speciální tabulka v datovém modelu, která se chová jinak než standardní tabulka
  • Obsahuje soubor "Calculation Items" — každá položka je transformace (YTD, PY, YoY%, atd.)
  • Automaticky se aplikuje na všechny measures v modelu přes "Apply Precedence"
  • Minimalizuje kód — místo 10 measures pro YTD/YoY/atd., máte jednu CG s 10 položkami

Tvorba Calculation Group v Tabular Editoru

1
Otevřete Tabular Editor

Connect to your Power BI model nebo Analysis Services.

2
Vytvořte novou tabulku a označte ji jako Calculation Group

V Tabular Editoru klikněte na tabulku → Properties → Set "Type" na "Calculation Group".

3
Přidejte Calculation Items

Například "Current Month", "Previous Month", "YTD", "YoY%".

Calculation Group Time Calculations — reálný příklad z modelu kurzu

Calculation Group Time Calculations v modelu kurzu obsahuje 4 položky. Výhoda: jedna skupina pokryje LY, VLY a VLY% pro všechny míry najednou.

DAX — calculationItem Actual
-- Vrátí míru beze změny
SELECTEDMEASURE()
DAX — calculationItem LY
CALCULATE(
    SELECTEDMEASURE()
    ,SAMEPERIODLASTYEAR('DimDate'[Date])
)
DAX — calculationItem VLY (Variance vs Last Year)
VAR _ty = SELECTEDMEASURE()
VAR _ly = CALCULATE(
    SELECTEDMEASURE()
    ,SAMEPERIODLASTYEAR('DimDate'[Date])
)
VAR _rslt =
    IF(ISBLANK(_ty) || ISBLANK(_ly), BLANK(), _ty - _ly)
RETURN _rslt
DAX — calculationItem VLY% (formatStringDefinition = "0.0%")
VAR _ty = SELECTEDMEASURE()
VAR _ly = CALCULATE(SELECTEDMEASURE(), SAMEPERIODLASTYEAR('DimDate'[Date]))
VAR _vly = IF(ISBLANK(_ty) || ISBLANK(_ly), BLANK(), _ty - _ly)
RETURN DIVIDE(_vly, _ly)

-- formatStringDefinition (dynamický formát jen pro VLY%):  "0.0%"

Dynamický formát (formatStringDefinition)

Pro VLY% je v modelu nastaveno formatStringDefinition = "0.0%". Ostatní položky dědí formát z vybrané míry. Tímto způsobem # Internet ukazuje v $, ale VLY% automaticky v procentech.

✓
Výhoda CG: Jakmile aplikujete CG na measure, automaticky se zobrazují všechny transformace. V Power BI visualizaci stačí přidat sloupec CG a measure se automaticky vypočítá pro všechny položky CG.
2.3

Field Parameters — přepínání metrik a dimenzí

Field Parameters (zavedeny v Power BI 2022) jsou uživatelsky přívětivější alternativou k Dynamic Measures. Automaticky generují možnosti výběru bez psaní SWITCH().

Tvorba Field Parameter v Power BI Desktop

1
V Power BI Desktop → Modeling tab → New Field Parameter

Pojmenujte: "Measure Selector" (nebo podobně)

2
Přidejte sloupce, které chcete povolit k přepínání

Vyberte: [Total Sales], [Total Profit], [Average Sale], atd.

3
Power BI automaticky vytvoří:

Tabulku "Measure Selector" s položkami a sloupcem "Value" s odkazem na měry. Vygeneruje measure "Measure Selector" s SWITCH logikou.

Praktické použití v visualizaci

  • Přidejte Field Parameter jako slicing (filtr): Uživatel si zvolí metriku → measure se dynamicky změní
  • Alternativa pro dimenze: Field Parameter pro přepínání mezi regionem/zemí/podkategorií v tabulce
DAX (Automaticky generované)
Measure Selector :=
SWITCH (
  TRUE (),
  SELECTEDVALUE ( MeasureSelector[MeasureSelector] ) = "Total Sales", [Total Sales],
  SELECTEDVALUE ( MeasureSelector[MeasureSelector] ) = "Total Profit", [Total Profit]
)
💡
Field Parameters vs. Dynamic Measures: Field Parameters jsou jednodušší pro uživatele (UI přepínač je automatizován), ale Dynamic Measures dávají více kontroly nad kódem. Používejte Field Parameters pro rychlé řešení, Dynamic Measures pro složitou logiku.
2.4

Dynamické časové kalkulace s řízeným posunem

Uživatelé často potřebují srovnávat různá období — minulý měsíc, loňský rok, poslední 3 měsíce. Implementujeme to přes parametry.

Parametrizovaný posun s DATEADD()

Třetí argument DATEADD musí být literálové klíčové slovo (DAY, MONTH, QUARTER, YEAR) — nelze ho předat jako textovou proměnnou. Pro přepínání typu intervalu použijte SWITCH:

DAX
-- SelectedInterval = SELECTEDVALUE z tabulky parametrů ("MONTH", "QUARTER", "YEAR")
TržbyPředchozíPerioda :=
VAR SelectedInterval = SELECTEDVALUE ( PeriodParameters[IntervalType], "MONTH" )
RETURN
SWITCH ( SelectedInterval,
  "MONTH",   CALCULATE ( [Total Sales], DATEADD ( DimDate[Date], -1, MONTH ) ),
  "QUARTER", CALCULATE ( [Total Sales], DATEADD ( DimDate[Date], -1, QUARTER ) ),
  "YEAR",    CALCULATE ( [Total Sales], DATEADD ( DimDate[Date], -1, YEAR ) )
)
-- Interval musí být literál (DAY/MONTH/QUARTER/YEAR), ne textová proměnná!
⚠️
DATEADD(DimDate[Date], -1, PeriodType) kde PeriodType = "MONTH" je neplatná syntaxe — DAX nevyhodnotí textovou proměnnou jako interval a vyhodí chybu. Třetí argument musí být vždy konstanta: DAY, MONTH, QUARTER, nebo YEAR.

Řízené srovnání s parametrem

Pro flexibilnější řešení vytvořte tabulku parametrů:

DAX
PeriodParameters := DATATABLE (
  "PeriodName", STRING,
  "DaysOffset", INTEGER,
  {
    { "Today", 0 },
    { "Yesterday", -1 },
    { "Last Week", -7 },
    { "Last Month", -30 }
  }
)

TržbyDynamicky :=
VAR SelectedOffset = SELECTEDVALUE ( PeriodParameters[DaysOffset], 0 )
RETURN
CALCULATE (
  [Total Sales],
  DATEADD ( DimDate[Date], SelectedOffset, DAY )
)
2.5

Object Level Security (OLS) — ochrana sloupců

Na rozdíl od Row Level Security (RLS), která filtruje řádky, Object Level Security skrývá celé sloupce nebo tabulky před určitými uživateli.

RLS vs. OLS

Vlastnost RLS OLS
Co filtruje? Řádky tabulky Sloupce/tabulky
Případ užití Prodejce vidí jen své tržby HR vidí platy, Finance ne
Nastavení V Power BI, RLS tab V Tabular Editoru

Implementace OLS v Tabular Editoru

1
Otevřete Tabular Editor a připojte model

Model musí být v režimu Import (ne DirectQuery pro OLS).

2
Pravý klik na sloupec/tabulku → Properties → Security

Nastavte "Allowed" nebo "Denied" role pro tento objekt.

3
Uložte a deploy do Power BI Service

Uživatelé přiřazení danému role nebudou vidět skrytý sloupec.

⚠
Omezení OLS: Skryté sloupce nemohou být použity v DAX výpočtech viditelných objektů (vrátí chybu). Plánujte strukturu modelu důsledně!

Praktický příklad: Skrytí platů v HR sloupci

  • Role "Finance": Má přístup ke sloupci [Salary]
  • Role "Operations": Nemá přístup ke sloupci [Salary]
  • Tabulka [Employee] zůstává viditelná (s výjimkou sloupce [Salary])
2.6

User Defined Functions a SVG vizualizace

DAX umožňuje tři způsoby, jak dosáhnout vizuální dynamiky bez Power BI vizuálů třetích stran: textové indikátory přes UNICHAR(), inline SVG obrázky generované DAX mírou, a od roku 2024 User Defined Functions (UDF) — pojmenované lambda funkce definované přímo v modelu pomocí TMDL.

ℹ
Předpoklady: UDF v TMDL vyžadují Tabular Editor 3 (placenou verzi) a Power BI Premium / Fabric nebo Analysis Services 2022+. UNICHAR a SVG míry fungují v základním Power BI Desktop.

2.6.1 UNICHAR indikátory — nejjednodušší varianta

Metoda nevyžaduje žádné speciální nastavení. Míra vrátí textový řetězec obsahující Unicode symbol šipky, který Power BI zobrazí jako text v kartě nebo tabulce.

SymbolUNICHAR()Použití
▲UNICHAR(9650)Kladná odchylka
▼UNICHAR(9660)Záporná odchylka
●UNICHAR(9679)Neutrální stav
★UNICHAR(9733)Hvězdičkové hodnocení
✓UNICHAR(10003)Splněno / OK

Nevýhoda: nelze přímo podmíněně formátovat barvu textu DAX mírou — barvu šipky nastavíte přes Podmíněné formátování v Power BI (Pravidla → Pole → tato míra).

Míra kombinuje šipkový symbol s hodnotou # VTGT (variance vůči cíli) z reálného modelu kurzu:

DAX
-- # VTGT z modelu: IF(ISBLANK([# TGT]), BLANK(), [# Internet] - [# TGT])
# VTGT Trend =
VAR _vtgt = [# VTGT]
VAR _symbol =
    IF(_vtgt >= 0,
        UNICHAR(9650),   -- ▲
        UNICHAR(9660)    -- ▼
    )
VAR _hodnota = FORMAT(ABS(_vtgt), "#,##0")
RETURN
    IF(
        ISBLANK(_vtgt),
        BLANK(),
        _symbol & " " & _hodnota
    )
💡
Výsledek ▲ 12 450 nebo ▼ 3 200. Podmíněné formátování → Barva písma → nastavte zelenou/červenou podle stejné míry # VTGT (číselná hodnota).

2.6.2 SVG progress bar — míra vrací obrázek

Power BI umí zobrazit sloupec nebo míru jako obrázek, pokud začíná prefixem data:image/svg+xml,. DAX míra sestaví celý SVG kód jako textový řetězec.

⚠
Důležité nastavení: Pro míru nelze nastavit datovou kategorii Image URL přímo. Místo toho je nutné vložit míru do tabulky přes Measure → New column s typem Text a kategorií Image URL, nebo použít calculated column s pevnou hodnotou a mírový výsledek zobrazit přes podmíněné formátování na dalším sloupci. V praxi nejjednodušší způsob: HTML vizuál z AppSource nebo DAX studia.

SVG je XML textový formát. Power BI akceptuje inline SVG v URI formátu — znaky jako # nesmí být v řetězci (Power BI je interpretuje jako konec URI). Řešení: pojmenované barvy (green, orange, red) místo hex kódů.

SVG prvekÚčel
<svg width='200' height='24'>Rozměry plátna
<rect fill='lightgray' rx='4'/>Pozadí se zaoblenými rohy
<rect width='_w' fill='green'/>Výplň dle hodnoty
<text text-anchor='middle'>Popis uprostřed

Míra aplikovaná na % TGT z reálného modelu (DIVIDE([# Internet], [# TGT])):

DAX
% TGT Bar =
VAR _pct   = [% TGT]
VAR _val   = MIN(1, MAX(0, _pct))         -- ořez 0–100 %
VAR _w     = ROUND(_val * 200, 0)         -- šířka výplně (0–200 px)
VAR _color =
    IF(_pct >= 1,   "green",
    IF(_pct >= 0.8, "orange",
                      "red"))
VAR _label = FORMAT(_pct, "0%")
RETURN
    IF(
        ISBLANK(_pct),
        BLANK(),
        "data:image/svg+xml,"
            & "<svg xmlns='http://www.w3.org/2000/svg' width='200' height='24'>"
            & "<rect width='200' height='24' fill='lightgray' rx='4'/>"
            & "<rect width='" & _w & "' height='24' fill='" & _color & "' rx='4'/>"
            & "<text x='100' y='17' text-anchor='middle' font-size='12'"
            & " font-family='Arial' fill='white' font-weight='bold'>"
            & _label
            & "</text></svg>"
    )
✓
Výsledek: zelená / oranžová / červená lišta se štítkem 87%. Pro zobrazení jako obrázek: v tabulkovém vizuálu nastavte sloupec → Image URL (datová kategorie na calculated column, který volá tuto míru).

2.6.3 User Defined Functions (UDF) — přepočet měny

V reálném modelu kurzu je přepočet CZK implementován jako calculated column Sales Original. UDF umožní stejnou logiku zavolat z libovolné míry přes SUMX — bez duplikace kódu.

Evoluce kódu: od calculated column k UDF

Krok 1 — reálný calculated column Sales Original z modelu▼

Calculated column v FactInternetSales — funguje díky row context, ale nelze volat z míry:

DAX — Calculated column (FactInternetSales)
Sales Original =
LOOKUPVALUE(
    FactCurrencyRate[EndOfDayRate],
    FactCurrencyRate[DateKey],    FactInternetSales[OrderDateKey],
    FactCurrencyRate[CurrencyKey], FactInternetSales[CurrencyKey]
) * FactInternetSales[SalesAmount]

Pro každý řádek faktu vyhledá směnný kurz v FactCurrencyRate pomocí dvou klíčů (datum + měna). Problém: duplikace logiky pokud chceme totéž pro FactResellerSales.

Krok 2 — míra s SUMX (row context uvnitř iterátoru)▼

SUMX iteruje řádky — uvnitř lambdy existuje row context a LOOKUPVALUE funguje:

DAX — Míra
# Internet CZK =
SUMX(
    FactInternetSales,
    LOOKUPVALUE(
        FactCurrencyRate[EndOfDayRate],
        FactCurrencyRate[DateKey],    FactInternetSales[OrderDateKey],
        FactCurrencyRate[CurrencyKey], FactInternetSales[CurrencyKey]
    ) * FactInternetSales[SalesAmount]
)

Funguje, ale opakujeme tu samou logiku LOOKUPVALUE pro každou míru a každý fact table. Pokud se změní struktura FactCurrencyRate, upravujeme na mnoha místech.

Krok 3 — TMDL UDF (Tabular Editor 3): ConvertToCZK▼

Funkce definovaná v TMDL jako pojmenovaný expression — volatelná z libovolné míry:

TMDL — Model expression (Tabular Editor 3 → Model → Expressions)
/// Přepočítá částku na CZK pomocí FactCurrencyRate
/// @param amount     Částka v původní měně
/// @param dateKey    OrderDateKey (integer YYYYMMDD)
/// @param currencyKey  Klíč měny z FactInternetSales nebo FactResellerSales
function ConvertToCZK(
    amount: Double,
    dateKey: Int64,
    currencyKey: Int64
) =
VAR _rate =
    LOOKUPVALUE(
        FactCurrencyRate[EndOfDayRate],
        FactCurrencyRate[DateKey],    dateKey,
        FactCurrencyRate[CurrencyKey], currencyKey
    )
RETURN
    IF(ISBLANK(_rate), amount, amount * _rate)

Volání z míry — logika přepočtu je na jednom místě:

DAX — Míry volající UDF
-- Internet Sales v CZK
# Internet CZK =
SUMX(
    FactInternetSales,
    ConvertToCZK(
        FactInternetSales[SalesAmount],
        FactInternetSales[OrderDateKey],
        FactInternetSales[CurrencyKey]
    )
)

-- Reseller Sales v CZK — stejná UDF, jiný fact table
# Reseller CZK =
SUMX(
    FactResellerSales,
    ConvertToCZK(
        FactResellerSales[SalesAmount],
        FactResellerSales[OrderDateKey],
        FactResellerSales[CurrencyKey]
    )
)
✓
DRY princip (Don't Repeat Yourself): logika LOOKUPVALUE existuje na jediném místě. Změna v FactCurrencyRate = oprava pouze v UDF, ne ve všech mírách.

2.6.4 UDF pro SVG — ProgressBarSVG

Stejný pattern — extrahujeme opakující se SVG kód do pojmenované funkce. Tím odděláme výpočet hodnoty od vizuální prezentace.

TMDL — function ProgressBarSVG
/// Vrátí SVG progress bar jako data URI
/// @param pct        Hodnota 0.0 – 1.0 (např. [% TGT])
/// @param fillColor  Barva výplně: "green", "orange", "red", atd.
function ProgressBarSVG(pct: Double, fillColor: String) =
VAR _val   = MIN(1, MAX(0, pct))
VAR _w     = ROUND(_val * 200, 0)
VAR _label = FORMAT(pct, "0%")
RETURN
    "data:image/svg+xml,"
        & "<svg xmlns='http://www.w3.org/2000/svg' width='200' height='24'>"
        & "<rect width='200' height='24' fill='lightgray' rx='4'/>"
        & "<rect width='" & _w & "' height='24' fill='" & fillColor & "' rx='4'/>"
        & "<text x='100' y='17' text-anchor='middle' font-size='12'"
        & " font-family='Arial' fill='white' font-weight='bold'>"
        & _label
        & "</text></svg>"

Míra pak volá UDF a předá hodnotu + barvu rozhodnutou v míře:

DAX — Míra volající UDF
% TGT Bar v2 =
VAR _pct   = [% TGT]
VAR _color =
    IF(_pct >= 1,   "green",
    IF(_pct >= 0.8, "orange",
                      "red"))
RETURN
    IF(
        ISBLANK(_pct),
        BLANK(),
        ProgressBarSVG(_pct, _color)
    )
💡
Výhoda abstrakce: Chceme změnit rozměry lišty ze 200 px na 120 px? Změníme ProgressBarSVG na jednom místě — všechny míry, které ji volají, se automaticky aktualizují. Bez UDF bychom hledali a upravovali každou míru zvlášť.
PřístupSložitostReusabilitaPožadavky
UNICHAR indikátorNízká—Power BI Desktop
SVG míra (inline)Střední—Power BI Desktop
UDF + SUMXStřední⭐⭐⭐Tabular Editor 3 + Premium/Fabric
UDF pro SVGNízká (volání)⭐⭐⭐Tabular Editor 3 + Premium/Fabric