Power BI in zes lessen

De complete masterclass voor Power BI - Leer data transformatie met Power Query, geavanceerde DAX formules, data modeling en professionele dashboard design.

6
Lessen
Beginner tot gevorderd
Niveau
6
Praktijkoefeningen
PL-300
Certificering Prep

Les 1: Power BI Fundamentals

90 minuten Beginner Inclusief Demo

Wat is Power BI? Het Complete Analytics Platform

Power BI is Microsoft's business intelligence en data visualisatie platform waarmee je data kunt transformeren, modelleren en visualiseren in interactieve dashboards en rapporten.

Key Insight

Power BI bestaat uit drie hoofdcomponenten: Power BI Desktop (gratis ontwikkelingstool), Power BI Service (cloud service voor delen en samenwerken), en Power BI Mobile (apps voor iOS en Android).

Power BI Architecture & Components

Data Sources

Excel, SQL, APIs, Cloud services

Power Query

ETL & data transformatie

Data Model

Relaties, star schema

DAX

Berekeningen & measures

Visualizations

Charts, tables, custom visuals

Power BI Service

Delen, samenwerken, gateways

Power BI vs Andere BI Tools

Feature Power BI Tableau Qlik Sense Excel
Prijs ✅ Gratis Desktop, €9.99/maand Pro ❌ €70/maand (Creator) ❌ €30/maand ✅ Onderdeel van Office 365
Microsoft Integration ✅ Uitstekend (Excel, Teams, Azure) ❌ Beperkt ❌ Beperkt ✅ Perfect
Learning Curve ✅ Matig (vooral DAX) ❌ Steil (M taal, complex) ❌ Steil (Scripting) ✅ Makkelijk (basis)
Data Modeling ✅ Uitstekend (in-memory) ❌ Beperkt ✅ Goed (associative) ❌ Zeer beperkt
AI Features ✅ Uitstekend (Copilot, AutoML) ✅ Goed (Einstein) ✅ Matig ❌ Zeer beperkt
Community & Resources ✅ Enorm (Microsoft ecosystem) ✅ Groot ✅ Matig ✅ Enorm

Pro Tip: Wanneer Power BI Kiezen?

Kies Power BI wanneer je: (1) Al in Microsoft ecosystem zit, (2) Goedkope oplossing nodig hebt, (3) Geavanceerde data modeling wil, (4) Sterke DAX berekeningen nodig hebt, (5) Veel wil integreren met Excel/Azure.

Je Eerste Power BI Rapport: Complete Demo

Power Query M - sales_transform.m

// Stap 1: Data laden van Excel
let
    Bron = Excel.Workbook(File.Contents("C:\Data\Sales.xlsx"), null, true),
    Sales_Sheet = Bron{[Item="Sales",Kind="Sheet"]}[Data],
    
    // Stap 2: Headers promoveren
    Headers = Table.PromoteHeaders(Sales_Sheet, [PromoteAllScalars=true]),
    
    // Stap 3: Data types instellen
    ChangedType = Table.TransformColumnTypes(Headers,{
        {"OrderID", Int64.Type},
        {"OrderDate", type date},
        {"CustomerID", Int64.Type},
        {"ProductID", Int64.Type},
        {"Quantity", Int64.Type},
        {"UnitPrice", Currency.Type},
        {"TotalAmount", Currency.Type},
        {"Region", type text},
        {"SalesPerson", type text}
    }),
    
    // Stap 4: Berekende kolom toevoegen
    AddYearMonth = Table.AddColumn(ChangedType, "YearMonth", 
        each Date.ToText([OrderDate], "YYYY-MM"), type text),
    
    // Stap 5: Filters toepassen
    FilteredRows = Table.SelectRows(AddYearMonth, each [TotalAmount] > 0),
    
    // Stap 6: Ongeldige data verwijderen
    RemoveNulls = Table.SelectRows(FilteredRows, each 
        not List.Contains({null, ""}, [CustomerID])),
    
    // Stap 7: Sorteren
    SortedRows = Table.Sort(RemoveNulls,{{"OrderDate", Order.Descending}})
in
    SortedRows

// Stap 8: Parameters voor hergebruik
RegionalSettings = [
    CurrencySymbol = "€",
    DecimalSeparator = ",",
    ThousandSeparator = "."
],

// Stap 9: Function voor herhaalbare transformaties
CleanCurrencyColumn = (table as table, columnName as text) as table =>
    let
        ReplaceSymbols = Table.ReplaceValue(table,
            each Record.Field(_, columnName),
            each Text.Replace(Text.Replace(_, "€", ""), ".", ""),
            Replacer.ReplaceText,
            {columnName}
        ),
        ToNumber = Table.TransformColumnTypes(ReplaceSymbols,
            {{columnName, Currency.Type}}
        )
    in
        ToNumber
        

DAX Voorbeelden: Je Eerste Measures & Calculated Columns

DAX - sales_measures.dax

// ========================
// BASICS MEASURES
// ========================

// Totale verkopen (basis measure)
Total Sales = SUM(Sales[TotalAmount])

// Aantal orders (COUNTROWS)
Total Orders = COUNTROWS(Sales)

// Aantal unieke klanten (DISTINCTCOUNT)
Unique Customers = DISTINCTCOUNT(Sales[CustomerID])

// Gemiddelde order waarde (AVERAGE)
Average Order Value = AVERAGE(Sales[TotalAmount])

// ========================
// TIME INTELLIGENCE
// ========================

// Verkopen dit jaar (TOTALYTD)
Sales YTD = TOTALYTD(
    [Total Sales],
    'Date'[Date],
    "31/12"  // Jaareinde
)

// Verkopen vorig jaar (SAMEPERIODLASTYEAR)
Sales Previous Year = 
CALCULATE(
    [Total Sales],
    SAMEPERIODLASTYEAR('Date'[Date])
)

// YoY groei percentage
Sales YoY Growth = 
DIVIDE(
    [Total Sales] - [Sales Previous Year],
    [Sales Previous Year],
    0
)

// Rolling 12 maanden (TRAILING 12 MONTHS)
Sales Rolling 12M = 
CALCULATE(
    [Total Sales],
    DATESINPERIOD(
        'Date'[Date],
        MAX('Date'[Date]),
        -12,
        MONTH
    )
)

// ========================
// CONDITIONAL MEASURES
// ========================

// Verkopen alleen voor premium klanten
Premium Sales = 
CALCULATE(
    [Total Sales],
    Customer[Segment] = "Premium"
)

// Verkopen boven €1000 (high-value orders)
High Value Sales = 
CALCULATE(
    [Total Sales],
    Sales[TotalAmount] > 1000
)

// Percentage van totale verkopen
Premium Sales % = 
DIVIDE(
    [Premium Sales],
    [Total Sales],
    0
)

// ========================
// RANKING & TOP N
// ========================

// Rangschikking van producten op verkopen
Product Sales Rank = 
RANKX(
    ALL(Product[ProductName]),
    [Total Sales],
    ,
    DESC,
    Dense
)

// Top 5 producten identificeren
Is Top 5 Product = 
VAR CurrentProductSales = [Total Sales]
VAR Top5Products = 
    TOPN(
        5,
        VALUES(Product[ProductName]),
        [Total Sales]
    )
RETURN
    IF(
        SELECTEDVALUE(Product[ProductName]) IN Top5Products,
        "Top 5",
        "Other"
    )

// ========================
// DYNAMIC FORMATTING
// ========================

// Voorwaardelijke opmaak op basis van target
Sales vs Target = 
VAR SalesAmount = [Total Sales]
VAR TargetAmount = [Sales Target]
RETURN
    SalesAmount - TargetAmount

// Format als € of %
Sales vs Target Formatted = 
VAR Difference = [Sales vs Target]
VAR TargetAmount = [Sales Target]
VAR Percentage = DIVIDE(Difference, TargetAmount, 0)
RETURN
    IF(
        ABS(Percentage) < 0.01,  // Kleine verschillen
        FORMAT(Difference, "€#,##0"),
        FORMAT(Percentage, "0.0%")
    )

// ========================
// AI-POWERED MEASURES
// ========================

// Voorbeeld met AI visuals (Quick Insights)
// Power BI kan automatisch patronen detecteren
// Gebruik: Home tab → Quick Insights

// ========================
// PERFORMANCE OPTIMALISATIE
// ========================

// Gebruik VARIABLES voor betere performance
Optimized Sales Calculation = 
VAR TotalRevenue = SUM(Sales[TotalAmount])
VAR TotalCost = SUM(Sales[CostAmount])
VAR TotalQuantity = SUM(Sales[Quantity])
RETURN
    DIVIDE(TotalRevenue - TotalCost, TotalQuantity, 0)

// ========================
// DUTCH SPECIFIC FORMATTING
// ========================

// Nederlands geld formaat met euro teken
Sales Formatted NL = 
FORMAT(
    [Total Sales],
    "€ #,##0.00;€ -#,##0.00;€ 0.00"
)

// Nederlandse datum formaten
Last Order Date NL = 
FORMAT(
    MAX(Sales[OrderDate]),
    "dd-MM-yyyy"
)

// Nederlandse duizend/miljoen afkortingen
Sales Abbreviated NL = 
VAR Value = [Total Sales]
RETURN
    SWITCH(
        TRUE(),
        Value >= 1000000, FORMAT(Value / 1000000, "0.0") & "M",
        Value >= 1000, FORMAT(Value / 1000, "0.0") & "K",
        FORMAT(Value, "0")
    ) & " €"

// ========================
// REAL-WORLD BUSINESS SCENARIO
// ========================

// Nederlandse BTW berekening (21%)
Sales Excluding VAT = 
DIVIDE([Total Sales], 1.21)

// Kwartaal performance vs vorig jaar
Sales Growth QoQ = 
VAR CurrentQuarter = [Total Sales]
VAR PreviousQuarter = 
    CALCULATE(
        [Total Sales],
        DATEADD('Date'[Date], -1, QUARTER)
    )
RETURN
    DIVIDE(
        CurrentQuarter - PreviousQuarter,
        PreviousQuarter,
        0
    )

// Customer segmentation gebaseerd op RFM
Customer Segment = 
VAR Recency = DATEDIFF(MAX(Sales[OrderDate]), TODAY(), DAY)
VAR Frequency = [Total Orders]
VAR Monetary = [Total Sales]
RETURN
    SWITCH(
        TRUE(),
        Recency <= 30 && Frequency >= 10 && Monetary >= 5000, "Champions",
        Recency <= 60 && Frequency >= 5, "Loyal Customers",
        Monetary >= 10000, "High Value",
        "Need Attention"
    )
        
Executive Sales Dashboard
Total Sales
€4.2M
+12% YoY
Orders
42,158
+8% YoY
Customers
2,415
+15% YoY
Avg Order
€99.63
+4% YoY
Monthly Sales Trend
Top Products
Product A €850K
Product B €720K
Sales by Region

Oefening: Bouw Je Eerste Dashboard

Scenario: Je werkt voor een Nederlandse retail keten met 50 winkels. Je krijgt:

  • Excel bestand met dagelijkse sales (100k+ rijen)
  • Product catalogus met categorieën en prijzen
  • Winkel locaties en metadata
  • Promotie kalender

Opdracht: Bouw een Power BI dashboard met:

  1. KPI's voor totale omzet, orders, gemiddelde orderwaarde
  2. Time intelligence: YTD, YoY groei, rolling 12 maanden
  3. Top 10 producten en categorieën
  4. Geografische weergave per winkel
  5. Segmentatie op klanttype (nieuw/terugkerend)
  6. What-if analyse voor prijsveranderingen

Real-World Case: Albert Heijn

Uitdaging: Albert Heijn had gefragmenteerde rapportages in Excel, trage refreshes, en geen real-time inzichten in winkels.

Oplossing met Power BI:

  • Gecentraliseerd data warehouse met Azure Synapse
  • Real-time Power BI dashboards per winkel
  • AI-powered forecasting voor voorraadbeheer
  • Mobile dashboards voor store managers
  • Power BI Premium voor enterprise sharing

Resultaat: 80% reductie in rapportage tijd, real-time inzicht in voorraad, 15% minder voedselverspilling door betere forecasting, en self-service analytics voor 500+ managers.

Power BI Visualization Gallery

Bar & Column Charts

Voor vergelijkingen tussen categorieën

Best voor: Sales per region, Product performance
Line Charts

Voor trends over tijd

Best voor: Sales trends, Growth metrics
Pie & Donut Charts

Voor proportionele verdelingen

Best voor: Market share, Budget allocation
Maps & Geospatial

Voor geografische data

Best voor: Regional sales, Store locations
AI Visuals

Voor geavanceerde analyses

Best voor: Forecasting, Anomaly detection

Power BI Knowledge Check

Vraag 1: Wat is het verschil tussen Power BI Desktop en Power BI Service?

A. Desktop is voor ontwikkeling, Service is voor delen/publiceren
B. Desktop is alleen voor Windows, Service voor Mac
C. Desktop heeft meer visuals dan Service
D. Service is gratis, Desktop kost geld

Vraag 2: Wat doet de CALCULATE functie in DAX?

A. Wijzigt de filtercontext van een berekening
B. Berekenent het gemiddelde van een kolom
C. Creëert een nieuwe tabel
D. Converteert tekst naar getallen

Vraag 3: Wat is Power Query in Power BI?

A. ETL tool voor data transformatie en cleaning
B. Een programmeertaal voor visuals
C. Een cloud service voor data opslag
D. Een AI tool voor forecasting

Les 2: Power Query en data voorbereiden

50 minuten Beginner Met M-voorbeelden

Waar je transformaties thuishoren

Power Query is de laag waar je data binnenkomt en wordt klaargemaakt. Alles wat je hier oplost, hoef je later niet met DAX te repareren — en dat scheelt meer dan je denkt, want DAX-berekeningen draaien bij elke klik opnieuw terwijl Power Query maar één keer per verversing werkt.

De vuistregel

Kun je iets in Power Query oplossen, doe het daar. Gebruik DAX alleen voor berekeningen die afhangen van wat de gebruiker aanklikt. Een kolom die altijd hetzelfde is, hoort in Power Query of nog beter in je bron.

Query folding: de belangrijkste knop die je niet ziet

Power Query probeert jouw stappen te vertalen naar een query die de bron zelf uitvoert. Filter je op jaar, dan stuurt hij een WHERE naar SQL Server en haalt alleen die rijen op. Dat heet folding, en het bepaalt of je verversing twee minuten of twee uur duurt.

Bepaalde stappen breken het folden: een aangepaste kolom met complexe M-code, Table.Buffer, of een stap die niet naar de brontaal te vertalen is. Alles ná die stap gebeurt in het geheugen van Power BI in plaats van in de bron.

Controleer het met één klik

Klik rechts op een stap en kijk of "View Native Query" beschikbaar is. Is hij grijs, dan is het folden daar gestopt. Zet je filters en verwijder je kolommen daarom altijd zo vroeg mogelijk, vóór de stappen die het folden breken.

M - orders_voorbereiden.m

let
    Bron = Sql.Database("server", "dwh"),
    Orders = Bron{[Schema="dbo", Item="orders"]}[Data],

    // Vroeg filteren: dit foldt naar een WHERE in de bron
    Gefilterd = Table.SelectRows(Orders, each [besteldatum] >= #date(2024, 1, 1)),

    // Kolommen weggooien die je niet gebruikt: scheelt geheugen in het model
    Beperkt = Table.SelectColumns(Gefilterd,
        {"order_id", "klant_id", "besteldatum", "bedrag", "status"}),

    // Types expliciet zetten; laat dit niet aan Power BI over
    Getypeerd = Table.TransformColumnTypes(Beperkt, {
        {"order_id",    Int64.Type},
        {"klant_id",    Int64.Type},
        {"besteldatum", type date},
        {"bedrag",      Currency.Type},
        {"status",      type text}
    })
in
    Getypeerd
        

Parameters in plaats van harde waarden

Zet servernamen en databasenamen in parameters. Dan verhuis je van acceptatie naar productie door één waarde te wijzigen, in plaats van twintig queries langs te gaan.

M - parameters.m

// Parameter pServer met als huidige waarde "sql-acc.bedrijf.nl"
let
    Bron = Sql.Database(pServer, pDatabase),
    Orders = Bron{[Schema="dbo", Item="orders"]}[Data]
in
    Orders

// Een functie die je op meerdere tabellen hergebruikt
let
    OpschonenTekst = (tabel as table, kolom as text) as table =>
        Table.TransformColumns(tabel, {{kolom, each Text.Trim(Text.Clean(_)), type text}})
in
    OpschonenTekst
        

Oefening: een trage verversing versnellen

Situatie: een rapport ververst in 45 minuten. De brontabel heeft 80 miljoen rijen en 60 kolommen; het rapport gebruikt er 8. De eerste stap voegt een aangepaste kolom toe met een complexe berekening, daarna wordt gefilterd op de laatste twee jaar.

Opdracht:

  1. Wat is er mis met de volgorde van de stappen?
  2. Hoe controleer je waar het folden stopt?
  3. Welke twee stappen zet je vooraan, en wat levert dat ongeveer op?
  4. Waar zou die complexe berekening eigenlijk thuishoren?

Richting: de aangepaste kolom staat vóór het filter en breekt waarschijnlijk het folden, waardoor alle 80 miljoen rijen en 60 kolommen worden opgehaald voordat er gefilterd wordt. Controleer met "View Native Query" waar het stopt. Zet eerst het filter op de laatste twee jaar en daarna de kolomselectie tot acht kolommen; dat alleen al kan een factor tien schelen. De berekening hoort in de bron als view of berekende kolom, zodat hij één keer per lading gebeurt in plaats van bij elke verversing.

Les 3: Datamodellering en het stermodel

50 minuten Gemiddeld Kern van Power BI

Waarom een stermodel en niet één grote tabel

De verleiding is groot om alles plat te slaan in één brede tabel. Dat werkt tot het niet meer werkt: je model wordt groot, je filters gedragen zich onvoorspelbaar en tijdsintelligentie gaat rammelen.

Een stermodel heeft feitentabellen in het midden met de meetbare gebeurtenissen, en dimensietabellen eromheen met de beschrijvende kenmerken. De engine achter Power BI is hier letterlijk voor gebouwd.

Onthoud dit

Filters stromen standaard van de dimensie naar het feit, nooit andersom. Dat is geen beperking maar de kern van het ontwerp: je klikt op een klant in de dimensie en de feiten worden gefilterd. Begrijp je die richting, dan begrijp je het meeste van DAX.

Vier fouten die je veel ziet

DAX - datumtabel.dax

dim_datum =
VAR MinDatum = MIN(fact_omzet[besteldatum])
VAR MaxDatum = MAX(fact_omzet[besteldatum])
RETURN
ADDCOLUMNS(
    CALENDAR(DATE(YEAR(MinDatum), 1, 1), DATE(YEAR(MaxDatum), 12, 31)),
    "Jaar",        YEAR([Date]),
    "Maandnr",     MONTH([Date]),
    "Maand",       FORMAT([Date], "mmmm"),
    "Kwartaal",    "Q" & ROUNDUP(MONTH([Date]) / 3, 0),
    "JaarMaand",   FORMAT([Date], "yyyy-mm"),
    "Weekdag",     FORMAT([Date], "dddd"),
    "IsWerkdag",   WEEKDAY([Date], 2) <= 5
)

-- Daarna: rechtsklik op de tabel, "Mark as date table", kolom Date.
-- Sorteer Maand op Maandnr, anders staat april vóór augustus.
        

Verberg wat niemand hoeft te zien

Verberg sleutelkolommen en ruwe feitkolommen in de rapportweergave. Gebruikers zien dan alleen de maatstaven en de dimensievelden die betekenis hebben. Dat voorkomt dat iemand per ongeluk een sleutel in een visual sleept en zich afvraagt waarom het antwoord onzin is.

Oefening: een model rechttrekken

Situatie: je erft een model met één tabel van 40 kolommen waarin orders, klantgegevens en productinformatie door elkaar staan. Er is geen datumtabel; er wordt gefilterd op een tekstkolom "maand". Een omzetvergelijking met vorig jaar geeft rare uitkomsten.

Opdracht:

  1. In welke tabellen splits je dit op?
  2. Waarom geeft de jaarvergelijking rare uitkomsten, en wat lost dat op?
  3. Welke kolommen maak je tot sleutel, en van welk type?
  4. Welke kolommen verberg je voor de rapportgebruiker?

Richting: splits in fact_orders met de meetbare velden en sleutels, plus dim_klant, dim_product en dim_datum. De jaarvergelijking faalt omdat een tekstkolom "maand" geen tijdsintelligentie ondersteunt — met een echte, gemarkeerde datumtabel werkt SAMEPERIODLASTYEAR wel. Maak gehele sleutels aan voor klant en product. Verberg alle sleutelkolommen en de ruwe bedragen, zodat gebruikers alleen expliciete maatstaven gebruiken.

Les 4: DAX en filtercontext

55 minuten Gevorderd Met DAX-voorbeelden

Het begrip dat alles verklaart

Bijna elke DAX-vraag komt neer op één onderwerp: filtercontext. Dat is het geheel aan filters dat geldt op het moment dat een maatstaf wordt berekend — afkomstig van de rij in je visual, van slicers, en van filters op pagina- of rapportniveau.

Zet je [Omzet] in een tabel met klanten, dan wordt diezelfde maatstaf per rij opnieuw berekend, elke keer met een andere filtercontext. De formule verandert niet; de context wel.

Wat CALCULATE werkelijk doet

CALCULATE is de enige functie die de filtercontext kan wijzigen. Alle gevorderde DAX draait om dat ene gegeven: je berekent iets, maar dan onder andere filters dan er nu gelden.

DAX - filtercontext.dax

Omzet = SUM(fact_orders[bedrag])

-- Een filter toevoegen
Omzet online = CALCULATE([Omzet], fact_orders[kanaal] = "Online")

-- Een filter weghalen: ALL negeert het filter op klant,
-- zodat je het totaal krijgt ongeacht welke rij je bekijkt
Omzet totaal = CALCULATE([Omzet], ALL(dim_klant))

-- Aandeel van het geheel
Aandeel % = DIVIDE([Omzet], [Omzet totaal])

-- ALLSELECTED respecteert wél wat de gebruiker in slicers koos
Aandeel in selectie % =
DIVIDE([Omzet], CALCULATE([Omzet], ALLSELECTED(dim_klant)))
        

Tijdsintelligentie

Deze functies lijken magisch maar doen één ding: ze vervangen het datumfilter door een ander datumbereik. Daarom hebben ze een echte datumtabel nodig.

DAX - tijdsintelligentie.dax

Omzet vorig jaar = CALCULATE([Omzet], SAMEPERIODLASTYEAR(dim_datum[Date]))

Omzet YTD = TOTALYTD([Omzet], dim_datum[Date])

Groei % =
VAR Huidig = [Omzet]
VAR Vorig  = [Omzet vorig jaar]
RETURN
    IF(
        NOT ISBLANK(Vorig),                  -- geen groei tonen zonder vergelijkbasis
        DIVIDE(Huidig - Vorig, Vorig)
    )

-- Voortschrijdend gemiddelde over 3 maanden
Omzet 3M gemiddeld =
AVERAGEX(
    DATESINPERIOD(dim_datum[Date], MAX(dim_datum[Date]), -3, MONTH),
    [Omzet]
)
        

Gebruik VAR, altijd

Een variabele wordt één keer berekend en daarna hergebruikt. Schrijf je [Omzet vorig jaar] drie keer in dezelfde formule, dan rekent de engine het ook drie keer uit. Met VAR is het één keer, en je formule wordt bovendien leesbaar.

Berekende kolom of maatstaf?

Een berekende kolom wordt één keer bij de verversing berekend en kost geheugen in het model. Een maatstaf wordt bij elke klik berekend en kost niets aan opslag. Kies een kolom als je erop wilt filteren of groeperen; kies een maatstaf voor alles wat je optelt of vergelijkt.

Oefening: percentages die niet kloppen

Situatie: je maakt een tabel met omzet per productcategorie en een kolom "aandeel in totaal". Die kolom toont overal 100 procent. De formule is DIVIDE([Omzet], [Omzet]) met een tweede maatstaf die ook gewoon SUM(fact_orders[bedrag]) is.

Opdracht:

  1. Waarom staat er overal 100 procent?
  2. Welke functie heb je nodig om het totaal te krijgen?
  3. De gebruiker wil dat het aandeel meebeweegt met zijn slicerselectie. Welke variant gebruik je dan?
  4. Waarom gebruik je DIVIDE en niet gewoon een deelteken?

Richting: beide maatstaven staan onder dezelfde filtercontext, dus teller en noemer zijn identiek — vandaar 100 procent. Je hebt CALCULATE([Omzet], ALL(dim_product)) nodig om het categoriefilter weg te halen. Moet het meebewegen met slicers, gebruik dan ALLSELECTED in plaats van ALL. En DIVIDE vangt deling door nul netjes af, waar een deelteken een foutwaarde in je visual zet.

Les 5: Rapporten die gelezen worden

45 minuten Gemiddeld Ontwerp

Begin bij de vraag, niet bij de visual

Een rapport dat niemand gebruikt is meestal gebouwd vanuit wat er kon, niet vanuit wat iemand wilde weten. Schrijf op welke beslissing dit rapport moet ondersteunen, en bouw dan terug.

De juiste grafiek voor de juiste vraag

Over taartdiagrammen

Mensen vergelijken hoeken slecht en lengtes goed. Bij meer dan drie segmenten wordt een taartdiagram raden. Een staafdiagram beantwoordt dezelfde vraag preciezer en in minder ruimte.

Prestaties van een rapportpagina

Elke visual is een aparte query. Twintig visuals op één pagina betekent twintig query's bij elke klik. Dat is de meest voorkomende reden dat een rapport traag aanvoelt terwijl het model prima is.

Meet voordat je gokt

Gebruik Performance Analyzer in Power BI Desktop. Die laat per visual zien hoeveel milliseconden de DAX-query kostte en hoeveel het tekenen zelf. Duurt de query lang, dan ligt het aan je model of je maatstaf; duurt het tekenen lang, dan heb je te veel datapunten in beeld.

Toegankelijkheid is geen bijzaak

Ongeveer één op de twaalf mannen is kleurenblind. Vertrouw dus nooit op kleur alleen om onderscheid te maken: voeg labels, vormen of patronen toe. Zorg daarnaast voor voldoende contrast tussen tekst en achtergrond, en geef elke visual een alternatieve tekst zodat een schermlezer hem kan beschrijven.

Oefening: een rapport dat niet gebruikt wordt

Situatie: het directierapport wordt nauwelijks geopend. Het heeft 22 visuals op één pagina, drie taartdiagrammen, een tabel met 40 kolommen, en laadt in 14 seconden. De directie vraagt steeds per mail om "even de omzet van vorige maand".

Opdracht:

  1. Wat zegt die mailvraag over het rapport?
  2. Welke twee ingrepen verlagen de laadtijd het snelst?
  3. Wat doe je met de drie taartdiagrammen?
  4. Hoe zou je de pagina indelen als je opnieuw begint?

Richting: als mensen per mail om een getal vragen dat in het rapport staat, kunnen ze het niet vinden — het rapport beantwoordt hun vraag niet zichtbaar genoeg. Minder visuals per pagina en een tabel die niet 40 kolommen ophaalt, zijn de snelste winst; meet eerst met Performance Analyzer welke visual de boosdoener is. Vervang de taartdiagrammen door staafdiagrammen. Begin opnieuw met bovenaan drie kaarten met de kerngetallen inclusief vergelijking met vorige maand, daaronder één lijndiagram met het verloop, en pas daarna detail op een tweede pagina.

Les 6: Publiceren, verversen en beveiligen

45 minuten Gemiddeld Beheer

Workspaces en apps

Een workspace is waar je bouwt; een app is wat je publiceert. Dat onderscheid is belangrijk: geef eindgebruikers toegang tot de app, niet tot de workspace. Anders zien ze je halve werk en kunnen ze dingen aanpassen die je niet wilt.

Richt minimaal twee workspaces in: één waar je ontwikkelt en één waar de gepubliceerde versie staat. Met deployment pipelines schuif je wijzigingen van de ene naar de andere.

Verversen inrichten

Een semantisch model in Import-modus moet ververst worden. Op een Pro-licentie mag dat acht keer per dag, op Premium of een Fabric-capaciteit achtenveertig keer. Staat je bron niet in de cloud, dan heb je een on-premises data gateway nodig.

Incrementeel verversen bij grote modellen

Met incrementeel verversen herlaadt Power BI alleen de recente periode en laat de historie staan. Een model van 200 miljoen rijen ververst dan in minuten in plaats van uren. Je stelt het in met twee parameters, RangeStart en RangeEnd, in Power Query — let erop dat je bron query folding ondersteunt, anders werkt het niet.

Row-level security

Met RLS bepaal je welke rijen iemand ziet. Je definieert rollen met een DAX-filter en wijst gebruikers aan die rol toe in de service. Test het altijd met "View as role" voordat je publiceert.

DAX - rls.dax

-- Rol "Regio": filter op de dimensietabel, niet op de feitentabel.
-- Het filter stroomt vanzelf door naar de feiten.
[regio] = LOOKUPVALUE(
    dim_medewerker[regio],
    dim_medewerker[email], USERPRINCIPALNAME()
)

-- Rol "Alles zien" voor de directie: geen filter, of expliciet
TRUE()
        

Twee valkuilen bij RLS

Filter op de dimensie en niet op het feit: dat is sneller en voorkomt rare uitkomsten bij meerdere relaties. En let op: een gebruiker die geen enkele rol toegewezen krijgt, ziet in de service niets in plaats van alles. Dat is veilig, maar leidt tot meldingen dat "het rapport leeg is".

Oefening: klaar voor productie

Situatie: je rapport is af en moet naar 120 accountmanagers die alleen hun eigen regio mogen zien. De bron is een SQL Server in het eigen datacenter. Het model telt 60 miljoen rijen en de volledige verversing duurt nu 90 minuten. Er is een Pro-licentie.

Opdracht:

  1. Via wat geef je de 120 mensen toegang, en waarom niet via de workspace?
  2. Wat heb je nodig om de SQL Server te kunnen verversen?
  3. Hoe breng je die 90 minuten omlaag?
  4. Hoe richt je de regiobeperking in, en hoe test je of het klopt?
  5. Welke licentiegrens loop je mogelijk tegenaan?

Richting: publiceer een app en geef daar toegang op, zodat niemand in je bouwomgeving komt. Voor de on-premises bron installeer je een data gateway in standaardmodus. De 90 minuten pak je aan met incrementeel verversen op de datumkolom — controleer wel of je query's folden, anders werkt het niet. RLS richt je in op de dimensie met USERPRINCIPALNAME() en test je met "View as role" plus een echte testgebruiker. Let op de Pro-grens: acht verversingen per dag en een modelgrootte van 1 GB; bij 60 miljoen rijen kan dat knellen, en dan is Premium per gebruiker of een Fabric-capaciteit het gesprek.

Power BI Carrière Kansen in Nederland

Power BI is de #1 gevraagde BI skill in Nederland. Gemiddelde salarissen (2024):

€40K - €55K
Junior Power BI Analyst
€55K - €75K
Power BI Developer
€70K - €95K+
Senior Power BI Consultant
€85K - €120K+
BI Architect

Tip: PL-300 Power BI Data Analyst certificering verhoogt je salaris met 20-30%. Nederlandse organisaties hebben enorme vraag naar Power BI experts.

Power BI Certificering Pad

Na deze masterclass ben je klaar voor:

PL-300: Power BI Data Analyst

Prepare, model, visualize and analyze data

DA-100: Analyzing Data

Data visualization and reporting (oudere certificering)

Microsoft Certified: Fabric

End-to-end analytics with Power BI and Fabric

Advanced DAX Specialist

Industry recognition for DAX expertise

Power BI Licensing Calculator

Power BI heeft verschillende licentie modellen. Bereken jouw kosten:

10 gebruikers

Geschatte maandelijkse kosten:

€99.90

Inclusief: Rapport creatie, delen & samenwerken, 8x daily refresh, 10GB storage

Power BI Learning Resources

Wat is Power BI?

Van databron tot rapport: de onderdelen, licenties en wanneer je wat gebruikt.

Lees het artikel

DAX-functies

De functies die je het vaakst nodig hebt, met uitleg over filtercontext en veelgemaakte fouten.

Lees het artikel

DAX-cheatsheet

Beknopt overzicht van de belangrijkste DAX-formules om naast je scherm te houden.

Bekijk de cheatsheet

Row-Level Security

Toegang per gebruiker inrichten: rollen, relaties en hoe je het test voordat het live gaat.

Lees het artikel

Jouw Power BI Learning Journey

Na deze masterclass kun je door naar:

Actuele Power BI Vacatures

Bekijk onze Power BI vacatures voor de nieuwste kansen bij Nederlandse top organisaties zoals banken, overheden, retail en consultancy.

Power BI vs Tableau vs Qlik - Dutch Market

Criterium Power BI Tableau Qlik Sense Google Looker
Marktaandeel NL ✅ 65% (dominant) 20% (zakelijk) 10% (niche) 5% (groeiend)
Kosten (per gebruiker/maand) €9.99 (Pro) €70+ (Creator) €30+ (Business) €25+ (Standard)
Learning Resources NL ✅ Uitstekend (veel NL content) Matig (veel Engelstalig) Beperkt Zeer beperkt
Microsoft Integratie ✅ Perfect Matig Beperkt Slecht
Vacatures in NL (2024) ✅ 850+ 120+ 45+ 30+
Toekomstperspectief ✅ Zeer sterk (Microsoft ecosystem) Stabiel (Salesforce) Afnemend Groeiend (Google Cloud)

In Nederland is Power BI de duidelijk marktleider met de meeste vacatures en beste carrièreperspectieven.