Dlaczego „te same” miary pokazują inne liczby
Autorowi raportu zależy zwykle na dwóch rzeczach: żeby liczby były poprawne oraz żeby nie zaskakiwały. Gdy miara DAX w jednym miejscu pokazuje jedną wartość, a po kliknięciu segmentu lub zmianie filtra – coś zupełnie innego – pojawia się wrażenie, że model danych żyje własnym życiem. Dochodzi nerwowe przeklikanie segmentów, sprawdzanie formuł, czasem nawet ręczne liczenie w Excelu „żeby udowodnić, że DAX się myli”.
Źródło zamieszania jest zawsze to samo: kontekst obliczeń. W Power Pivot (i w DAX ogólnie) żadna miara nie liczy „w próżni”. Miara zawsze odpowiada na pytanie: „Jaka jest wartość tego wyrażenia w aktualnie aktywnym kontekście filtra?”. Gdy zmieniają się segmenty, pola w tabeli przestawnej lub filtry raportu, pytanie, na które odpowiada miara, też się zmienia – a wraz z nim wynik.
Pierwszy zgrzyt: suma w tabeli vs suma w przestawnej
Najczęstszy scenariusz: użytkownik Excela ma tabelę z danymi sprzedażowymi. Dodaje na końcu kolumny Kwota formułę =SUMA(Kwota) i otrzymuje jakąś liczbę. Potem ładuje te same dane do modelu danych, tworzy tabelę przestawną z miarą Suma Sprzedaży = SUM(Sprzedaż[Kwota]) i… suma ogółem w przestawnej różni się od tej w klasycznym arkuszu. Zaczyna się podejrzenie, że Power Pivot coś filtruje, pomija wiersze, albo że relacje „uciekają” część danych.
W rzeczywistości klasyczna formuła Excela liczy po prostu wszystko, co widać w kolumnie – często razem z ukrytymi wierszami, bez świadomości relacji, segmentów czy filtrów raportu. Miara DAX działa inaczej: uruchamia się zawsze w konkretnym kontekście filtra, nadanym przez tabelę przestawną, segmenty, relacje i inne miary. Dlatego ta sama definicja miary może w jednym miejscu objąć wszystkie wiersze tabeli faktów, a w innym tylko mały ich wycinek.
Dlaczego wynik zmienia się po kliknięciu segmentu
Segment (Slicer) nie zmienia formuły miary, nie modyfikuje kodu DAX. Dokłada filtr do modelu danych. Z perspektywy miary oznacza to, że zestaw wierszy, na których liczy się SUM, AVERAGE czy cokolwiek innego, staje się węższy. Funkcja pozostaje ta sama, ale działa na innej podtabeli danych – „przyciętej” przez aktualne filtry.
Przykład praktyczny:
- bez segmentu „Rok” miara [Suma Sprzedaży] obejmuje wszystkie lata w tabeli Sprzedaż,
- po wybraniu 2023 w segmencie „Rok” ta sama miara liczy tylko wiersze, gdzie Rok = 2023,
- po włączeniu dodatkowego segmentu „Kraj” = „Polska” zostają wyłącznie wiersze Rok = 2023 i Kraj = „Polska”.
Formuła jest identyczna, ale zapytanie „ile wynosi suma sprzedaży?” zamienia się w „ile wynosi suma sprzedaży w Polsce w 2023 roku?”. Stąd wrażenie, że miara się „przepisała”, choć zmienił się wyłącznie kontekst filtra.
Emocje: poczucie braku kontroli i „magiczne” wyniki
Jeśli model danych jest rozbudowany, dochodzą segmenty połączone z kilkoma tabelami, relacje aktywne i nieaktywne, filtry poziomów szczegółowości (produkt, kategoria, marka). Wtedy pojedyncza komórka przestawnej ma na sobie jednocześnie kilkanaście filtrów. Gdy wynik miary drastycznie spada lub robi się pusty, naturalną reakcją jest myśl: „coś się wyłożyło”. W rzeczywistości DAX jest bezlitosnie konsekwentny: jeśli w danym kontekście filtra nie ma żadnych wierszy spełniających wszystkie warunki, wynik będzie BLANK() – i to często właśnie oznacza, że wszystko działa poprawnie.
Świadome korzystanie z miar zaczyna się w momencie, gdy zamiast szukać magicznych błędów, zadajesz sobie jedno krótkie pytanie: „Jaki dokładnie kontekst filtra obowiązuje dla tej komórki?”. Cała reszta to już kwestia kilku narzędzi w DAX, które pozwalają ten kontekst odczytać, zmienić lub tymczasowo zawiesić.

Podstawy modelu danych: skąd biorą się liczby w Power Pivot
Zanim przejdzie się do kontekstu filtrowania DAX, dobrze jest osadzić go w prostym modelu. Bez zrozumienia, jak działa przepływ filtrów w modelu danych, większość problemów z „dziwnymi” miarami wraca jak bumerang.
Model danych vs zwykła tabela przestawna
Klasyczna tabela przestawna w Excelu może być oparta na zakresie komórek lub tabeli Excela. Nie zna relacji, nie ma świadomości kalendarza czy wielu tabel faktów. Wszystkie pola pochodzą z jednego źródła, a filtry zachowują się dość intuicyjnie: filtrujesz jedną kolumnę zakresu, filtr działa tylko tam.
Model danych wprowadza struktury znane z baz danych:
- kilka tabel (faktów i wymiarów),
- relacje między nimi,
- kardynalność (jeden-do-wielu),
- kierunek propagacji filtrów.
Tabela przestawna podpięta do modelu danych staje się tak naprawdę interfejsem do zapytań na bazie kolumnowej. Gdy przeciągasz pole Rok z tabeli Kalendarz do wierszy, a miarę [Suma Sprzedaży] z tabeli Sprzedaż do wartości, Excel nie sumuje już bezpośrednio komórek, ale zadaje zapytanie do modelu: „podaj sumę kolumny Sprzedaż[Kwota] dla każdego roku z tabeli Kalendarz”.
Fakty i wymiary – prosta, ale kluczowa różnica
Najczęściej dane dzielą się na dwa typy tabel:
- tabele faktów – długie, z wieloma wierszami; przechowują zdarzenia: transakcje, logi, zdarzenia produkcyjne,
- tabele wymiarów – krótkie, opisowe; zawierają listę produktów, klientów, dat, regionów.
Przykładowy zestaw:
- Sprzedaż – fakt (kolumny: DataID, ProduktID, KlientID, Kwota),
- Produkty – wymiar (ProduktID, Nazwa, Kategoria, Marka),
- Kalendarz – wymiar (DataID, Data, Rok, Miesiąc, Kwartał),
- Regiony – wymiar (RegionID, Region, Kraj).
Tabela faktów łączy wszystkie wymiary poprzez klucze techniczne (ID). Dzięki temu pojedynczy wiersz sprzedaży można opisać jako „sprzedaż produktu X, klientowi Y, w dacie Z, w regionie W”. DAX nie interesuje się samym ID; korzysta z relacji, żeby połączyć te światy i zastosować odpowiednie filtry.
Relacje i propagacja filtrów
Relacja w modelu danych to połączenie kolumny po stronie „jeden” z kolumną po stronie „wiele”. Zwykle:
- po stronie jeden stoi wymiar (np. Produkty[ProduktID]),
- po stronie wiele stoi fakt (np. Sprzedaż[ProduktID]).
Gdy w tabeli przestawnej filtrowany jest Produkt = „A”, filtr działa na tabelę Produkty, a następnie propaguje się do tabeli Sprzedaż, ograniczając ją tylko do wierszy, gdzie Sprzedaż[ProduktID] odpowiada ProduktID produktu „A”. W rezultacie miara SUM(Sprzedaż[Kwota]) liczy tylko wiersze sprzedaży dla tego konkretnego produktu.
Ten kierunek jest jednostronny: filtr może płynąć z wymiaru do faktu, ale już nie odwrotnie (w standardowym, jednokierunkowym modelu). Gdy więc przeciągniesz pole z tabeli faktów do segmentu, możesz uzyskać zaskakujące wyniki, bo filtr nie zawsze wróci do wymiaru tak, jak się tego intuicyjnie oczekuje.
Przykładowy schemat modelu używanego dalej
Dla spójności rozważań przyjmijmy prosty model:
- tabela Sprzedaż – fakt,
- tabela Produkty – wymiar, połączona po ProduktID,
- tabela Kalendarz – wymiar, połączona po DataID,
- tabela Klienci – wymiar, połączona po KlientID.
Relacje: każdy wymiar jest połączony z tabelą Sprzedaż relacją jeden-do-wielu, z kierunkiem filtrów od wymiaru do faktu. Segmenty są oparte na wymiarach (np. Rok z Kalendarz, Kraj z Klienci, Kategoria z Produkty). Miary główne znajdują się w tabeli Sprzedaż.
Taki model pokrywa większość biznesowych scenariuszy i jednocześnie jest wystarczająco prosty, żeby krok po kroku wytłumaczyć, skąd biorą się różne wyniki tej samej miary po zmianie filtra lub segmentu.
Kontekst wiersza i kontekst filtra – dwa fundamenty DAX
W DAX kontekst to środowisko, w którym wykonywane jest obliczenie. Użytkownicy, którzy przeskakują z Excela, często zakładają, że każda formuła „widzi” wszystkie dane tak samo. W Power Pivot to założenie nie działa. Zamiast tego istnieją dwa główne typy kontekstu: kontekst wiersza i kontekst filtra.
Kontekst wiersza – perspektywa pojedynczego rekordu
Kontekst wiersza obowiązuje, gdy formuła jest ewaluowana w konkretnej linii tabeli. Najprościej obserwuje się go w kolumnach obliczanych. Jeśli tworzysz w tabeli Sprzedaż kolumnę:
= Sprzedaż[Kwota] * 0,23
to dla każdego wiersza formuła widzi wartości tylko z tego wiersza. Nie interesują jej inne transakcje, inne daty czy klienci. To typowe zachowanie „wiersz po wierszu”, znane też częściowo z Excela (adresy bezwzględne/półbezwzględne).
Kontekst wiersza pojawia się także w funkcjach iterujących (np. SUMX, AVERAGEX), gdzie DAX przechodzi po kolejnych wierszach wirtualnej tabeli i w każdym z nich uruchamia formułę, tworząc tymczasowy kontekst wiersza dla danego rekordu.
Kontekst filtra – zestaw aktywnych ograniczeń
Kontekst filtra to zestaw wszystkich filtrów, które są w danym momencie aktywne dla obliczenia. Może pochodzić z różnych źródeł:
- z pól w wierszach i kolumnach tabeli przestawnej,
- z filtrów raportu,
- z wybranych wartości w segmentach,
- z propagacji filtrów przez relacje,
- z funkcji DAX, które modyfikują kontekst (np. CALCULATE, FILTER).
Miary działają zawsze w kontekście filtra. Gdy piszesz miarę [Suma Sprzedaży] = SUM(Sprzedaż[Kwota]), nie mówisz DAX-owi „licz zawsze wszystko”. Instrukcja brzmi bardziej jak: „dodaj wartości kolumny Kwota ze wszystkich wierszy, które przetrwały aktualne filtry”. Dlatego ta sama miara zwróci inną wartość:
- w komórce ogółem (bez filtrów),
- w wierszu Produkt = „A”,
- w wierszu Rok = 2023 i kolumnie Kraj = „Polska”,
- po zaznaczeniu w segmencie tylko dwóch kategorii produktów.
Miary a kolumny obliczane – inne źródła kontekstu
Kolumna obliczana z definicji pracuje w kontekście wiersza. Jeśli w jej formule użyjesz np. SUM(Sprzedaż[Kwota]), DAX policzy sumę w kontekście filtra odpowiadającym temu wierszowi – co daje interesujące, ale często nieoczekiwane efekty. Miara natomiast nigdy nie ma kontekstu wiersza z samej siebie; korzysta wyłącznie z kontekstu filtra nadanego z zewnątrz.
W praktyce oznacza to, że:
- miary są projektowane z myślą o pracy w tabelach przestawnych, wykresach, macierzach – czyli tam, gdzie kontekst filtra zmienia się dynamicznie,
- kolumny obliczane służą głównie do wyprowadzania dodatkowych atrybutów na poziomie pojedynczego wiersza (np. rok z daty, segment z wartości liczbowej, flaga TAK/NIE).
Przykład: ta sama miara w różnych miejscach raportu
Miara:
[Suma Sprzedaży] = SUM(Sprzedaż[Kwota])
Jej zachowanie:
- w komórce ogółem (bez pól w wierszach/kolumnach, bez segmentów) – suma kwoty wszystkich wierszy w tabeli Sprzedaż,
- po dodaniu Produkty[Nazwa] do wierszy – w każdej linii suma kwoty tylko dla tego produktu, bo kontekst filtra zawiera teraz warunek „Produkt = bieżący wiersz”,
- po dodaniu Kalendarz[Rok] do kolumn – w każdej komórce skrzyżowania produktu i roku suma kwoty dla pary (Produkt, Rok),
- po zaznaczeniu w segmencie Kraj = „Polska” – wszystkie powyższe wyniki dodatkowo ograniczone do sprzedaży w Polsce.

Jak segmenty, filtry i pola przestawnej tworzą kontekst
Moment, w którym „ta sama” miara zaczyna zwracać inne wyniki, pojawia się dokładnie wtedy, gdy zmienia się kontekst filtra. A ten kontekst nie jest czymś abstrakcyjnym – tworzą go bardzo konkretne elementy raportu: pola w wierszach i kolumnach tabeli przestawnej, segmenty, filtry raportu oraz relacje między tabelami.
Pola w wierszach i kolumnach – lokalne filtry dla każdej komórki
Każda komórka tabeli przestawnej ma swój własny zestaw filtrów. To, co widzisz jako „etykietę wiersza” czy „etykietę kolumny”, DAX widzi jako warunek filtrujący. Jeśli w wierszach są Produkty[Nazwa], a w kolumnach Kalendarz[Rok], to pojedyncza komórka w skrzyżowaniu Produkt = „A” i Rok = 2023 ma kontekst filtra złożony co najmniej z dwóch warunków:
- Produkty[Nazwa] = „A”,
- Kalendarz[Rok] = 2023.
Jeśli do tego dochodzi filtr raportu (np. Kraj = „Polska”), komórka dostaje jeszcze trzeci warunek. Miara [Suma Sprzedaży] nie „wie”, gdzie dokładnie leży – dostaje po prostu informację: „to jest komórka, w której obowiązuje taki, a taki zestaw filtrów, policz sumę dla tego wycinka danych”.
Stąd bierze się efekt, który często budzi niepokój: suma po wierszach nie zawsze równa się wartości ogółem. Powód bywa prosty: pola w wierszach/kolumnach nakładają inny zestaw filtrów niż komórka „Total”, w której te pola w ogóle nie filtrują – przez co miara widzi szerszy lub węższy zakres danych.
Segmenty – zewnętrzny, wspólny filtr dla kilku wizualizacji
Segment (slicer) to nic innego jak interfejs do ustawiania filtrów na wybraną kolumnę tabeli. Kiedy w segmencie Rok zaznaczasz 2023 i 2024, to:
- filtrowana jest tabela Kalendarz tak, aby pozostały tylko wiersze z tymi latami,
- filtr propaguje się po relacjach do tabeli Sprzedaż,
- każda miara w każdej tabeli przestawnej/wykresie, powiązana z tym samym modelem danych, pracuje już w tym ograniczonym kontekście.
Dlatego zmiana jednego segmentu potrafi zmienić wartości we wszystkich powiązanych wizualizacjach naraz. I dlatego czasem dwie tabele przestawne, używające tej samej miary, pokazują różne wyniki – po prostu są podpięte do innych segmentów lub filtrów raportu.
Częsta sytuacja z praktyki: raport miesięczny i roczny obok siebie. Segment Rok podłączony tylko do raportu rocznego. Użytkownik zaznacza w segmencie „2024” i zastanawia się, czemu miesięczne zestawienie „nic nie reaguje”. Z punktu widzenia DAX-a wszystko jest poprawne – kontekst filtra po prostu nie jest współdzielony, więc miara liczy na różnych zbiorach danych.
Filtry raportu i filtry wizualizacji – cichy, ale mocny wpływ na liczby
Oprócz pól w wierszach/kolumnach i segmentów działają jeszcze inne źródła filtrów: filtr raportu (Report Filter) oraz filtry nakładane na konkretną tabelę przestawną lub wykres (np. przez menu filtrów lub w Power BI – panel Filters). One rzadziej rzucają się w oczy, a potrafią całkowicie zmienić znaczenie liczby.
Jeśli na poziomie raportu ustawisz Kraj = „Polska”, wszystkie miary w tym raporcie zaczną działać tak, jakby Polska była jedynym dostępnym krajem. Dopiero funkcje typu ALL czy REMOVEFILTERS potrafią ten filtr „zignorować” dla danego obliczenia, co tłumaczy, dlaczego miara „udział procentowy w całości” często jest większa niż 100% – liczy się względem innej całości niż podpowiada intuicja użytkownika.
Relacje – jak filtr „podróżuje” między tabelami
Kontekst filtra nie działa wyłącznie w obrębie jednej tabeli. Gdy ustawiasz filtr na wymiarze (np. Produkty[Kategoria] = „A”), filtr podróżuje do tabeli faktów (Sprzedaż) przez relację jeden-do-wielu. Dzięki temu miara w Sprzedaż widzi już tylko te wiersze, które spełniają warunki z wymiaru.
W kierunku odwrotnym filtr z reguły nie płynie. Jeśli np. w tabeli przestawnej dodasz Sprzedaż[ProduktID] do segmentu, niekoniecznie otrzymasz oczekiwane zachowanie, bo filtr na ID faktu nie „wróci” do wymiaru Produkty. Model jednokierunkowy jest tu bardzo dosłowny: filtry idą od wymiarów do faktów, nie odwrotnie. Dla miar oznacza to, że:
- najstabilniej jest opierać segmenty i filtry na tabelach wymiarów,
- segmenty oparte na faktach mogą dawać wyniki, które trudno wyjaśnić słownie użytkownikom końcowym.
Przykład: ta sama miara w dwóch tabelach – dwie różne „prawdy”
Wyobraź sobie dwa zestawienia:
- pierwsze pokazuje sprzedaż według Produktu i Roku, bez żadnych dodatkowych filtrów,
- drugie pokazuje sprzedaż według Klienta, ale na poziomie raportu nałożono filtr Kraj = „Niemcy”.
W obu użyta jest ta sama miara [Suma Sprzedaży]. Gdy porównisz „suma ogółem” z obu tabel, liczby się nie zgadzają. Z perspektywy DAX-a wszystko jest logiczne:
- pierwsza tabela pracuje w kontekście „wszystkie kraje”,
- druga – w kontekście „tylko Niemcy”.
Miara nie jest „inna” ani „zepsuta” – dostała po prostu inny zestaw filtrów. Gdybyś do pierwszej tabeli dodał ten sam filtr Kraj = „Niemcy”, liczby nagle by się wyrównały.

CALCULATE – serce zmieniających się miar
Dotąd kontekst filtra był tworzony głównie „z zewnątrz”: przez tabelę przestawną, segmenty i relacje. CALCULATE pozwala zrobić coś znacznie mocniejszego – zmienić lub rozszerzyć ten kontekst wewnątrz samej formuły miary. To właśnie tu zaczyna się większość „magicznych” zachowań, które na pierwszy rzut oka wyglądają jak sprzeczność.
Co tak naprawdę robi CALCULATE
Składnia w uproszczeniu:
CALCULATE(
wyrażenie,
filtr1,
filtr2,
...
)
Można ją czytać jak zdanie: „policz to wyrażenie, ale w innym kontekście filtra – takim, który powstanie po zastosowaniu filtr1, filtr2, … na bazie obecnego kontekstu”. CALCULATE:
- przejmuje aktualny kontekst filtra (z tabeli przestawnej, segmentów itd.),
- modyfikuje go zgodnie z dodatkowymi filtrami w argumentach,
- w nowym kontekście ponownie ocenia wyrażenie.
To oznacza, że ta sama miara, użyta w różnych miejscach raportu, może w środku siebie wywoływać CALCULATE, który jeszcze raz zmieni filtry. Efekt: „ta sama” komórka (np. Total) potrafi pokazywać inne liczby w zależności od tego, z czego składa się formuła.
CALCULATE jako „zmieniacz kontekstu”
Najprostsze przykłady użycia CALCULATE związane są z filtrowaniem po konkretnych wartościach:
[Sprzedaż Polska] =
CALCULATE(
[Suma Sprzedaży],
Klienci[Kraj] = "Polska"
)
Ta miara zawsze liczy sprzedaż tylko dla kraju „Polska”, niezależnie od tego, co zostanie wybrane w segmencie Kraj. Dzieje się tak, ponieważ CALCULATE nadpisuje filtr na kolumnie Klienci[Kraj]. Jeśli użytkownik wybierze w segmencie „Niemcy”, dla miary [Suma Sprzedaży] kontekst będzie wynosił „Kraj = Niemcy”, ale dla [Sprzedaż Polska] – „Kraj = Polska”. Stąd różne wyniki w tej samej komórce.
Inny przykład, często spotykany przy planach vs wykonaniu:
[Sprzedaż Bieżący Rok] = [Suma Sprzedaży]
[Sprzedaż Poprzedni Rok] =
CALCULATE(
[Suma Sprzedaży],
SAMEPERIODLASTYEAR(Kalendarz[Data])
)
Użytkownik wybiera w segmencie Rok = 2023. Miara [Sprzedaż Bieżący Rok] pracuje w naturalnym kontekście filtra (Rok = 2023), a [Sprzedaż Poprzedni Rok] przenosi ten kontekst w czasie, używając funkcji czasu i ponownie liczy sprzedaż, ale już dla 2022. Efekt końcowy: w tej samej komórce widzisz wartość bieżącego roku i poprzedniego – choć raport filtruje tylko bieżący rok.
Jak CALCULATE łączy się z kontekstem filtra z tabeli przestawnej
Dla wielu osób pułapką jest myślenie o CALCULATE jak o „liczeniu od zera”. Tymczasem domyślnie CALCULATE nie odcina wszystkich filtrów – on pracuje na tym, co już istnieje. Dopiero konkretne funkcje filtrujące (np. ALL, REMOVEFILTERS) potrafią oczyścić kontekst.
Przykładowo, w komórce dla Produkt = „A” i Rok = 2023:
- zwykła miara
[Suma Sprzedaży]działa przy filtrze (Produkt = „A”, Rok = 2023), - miara
[Sprzedaż Polska]działa przy filtrze (Produkt = „A”, Rok = 2023, Kraj = „Polska”), - miara używająca
ALL(Kalendarz)może pracować przy filtrze (Produkt = „A”, Kraj = „Polska”), ale już bez ograniczenia do roku 2023.
To właśnie trzeci przypadek powoduje, że użytkownik patrzący na kolumnę 2023 widzi wartości, które wcale nie są tylko za 2023 – bo w środku formuły ktoś użył CALCULATE z odfiltrowaniem kolumn z tabeli Kalendarz.
CALCULATE i przejście z kontekstu wiersza do filtra
CALCULATE ma jeszcze jedną istotną właściwość: gdy używany jest w kolumnie obliczanej lub funkcji iterującej (SUMX, AVERAGEX itp.), potrafi zmienić kontekst wiersza w kontekst filtra. To brzmi technicznie, ale w praktyce oznacza na przykład:
- w kolumnie obliczanej możesz odwołać się do sumy „po tabeli” dla bieżącego wiersza,
- w miarze iterującej po produktach możesz w każdej iteracji policzyć sumę tylko dla jednego produktu, mimo że nie ma go fizycznie w wierszach tabeli przestawnej.
Tak powstają miary w rodzaju „marża na produkt jako procent całkowitej sprzedaży produktu” liczone w różnych przekrojach. Gdy w formule pojawia się CALCULATE, uruchamia się mechanizm: weź bieżący wiersz iteracji (np. produkt X), zrób z niego filtr (Produkt = X), połącz z istniejącymi filtrami z raportu, a dopiero potem policz [Suma Sprzedaży]. Wynik może się radykalnie zmienić przy każdym innym układzie pól w raporcie, choć sama formuła się nie zmienia.
Funkcje kontekstowe w praktyce: ALL, REMOVEFILTERS, KEEPFILTERS, VALUES
Gdy CALCULATE staje się codziennością, szybko pojawia się kolejne pytanie: jak dokładnie sterować tym, które filtry mają obowiązywać, a które trzeba pominąć lub wzmocnić? Tu pojawiają się funkcje kontekstowe. To one decydują, czy miara liczy „z pełnego koszyka”, „w ramach tego, co widać na ekranie”, czy „mimo wybranych segmentów”.
ALL – policz „ponad” bieżącymi filtrami
ALL usuwa filtry z wybranej tabeli lub kolumny. Używany wewnątrz CALCULATE pozwala policzyć wartość tak, jakby pewnych filtrów w ogóle nie było. Klasyczny przykład to udział procentowy:
[Suma Sprzedaży] = SUM(Sprzedaż[Kwota])
[Suma Sprzedaży Ogółem] =
CALCULATE(
[Suma Sprzedaży],
ALL(Sprzedaż)
)
[% Udział w Całości] = DIVIDE([Suma Sprzedaży], [Suma Sprzedaży Ogółem])
Miara [% Udział w Całości] w wierszu Produkt = „A” liczy:
- w liczniku – sprzedaż produktu A w bieżącym kontekście (np. w danym roku, kraju, segmencie),
- w mianowniku – sprzedaż wszystkich produktów w tym samym kontekście, ale już bez filtrów na tabeli Sprzedaż (czyli niezależnie od produktu, kategorii itd.).
Jeśli zastosujesz ALL na tabeli wymiaru (np. ALL(Produkty)), efekt będzie inny: usuniesz filtry na produktach, ale pozostaną filtry na innych tabelach (np. Rok, Kraj). Subtelna różnica, która łatwo wyjaśnia, dlaczego „udział w całości” czasem odnosi się do całości roku w danym kraju, a czasem do całości absolutnej bez względu na czas i region.
REMOVEFILTERS – czytelniejszy sposób na „wyczyszczenie” kontekstu
Funkcja REMOVEFILTERS działa podobnie do ALL w kontekście usuwania filtrów, ale nie zmienia zestawu dostępnych wartości. Jest przydatna tam, gdzie zależy bardziej na czytelności formuły niż na dodatkowych efektach ALL (np. przy obliczaniu różnych rankingów).
REMOVEFILTERS w typowych miarach „ignorujących raport”
Dobrym sposobem na oswojenie REMOVEFILTERS jest spojrzenie na konkretne scenariusze, w których użytkownicy najczęściej łapią się za głowę: „przecież ustawiłem filtr na rok, a miara nadal liczy coś innego”. To wcale nie musi być błąd – często to świadoma decyzja twórcy modelu.
Wyobraź sobie prostą parę miar do analizy realizacji celu sprzedaży:
[Suma Sprzedaży] = SUM(Sprzedaż[Kwota])
[Cel Roczny] = SUM(Cele[Kwota_Celu])
[Realizacja %] = DIVIDE([Suma Sprzedaży], [Cel Roczny])
W takim zestawie zmiana filtrów (rok, kraj, produkt) wpływa zarówno na sprzedaż, jak i na cel. Czasem jednak przydaje się miara, która zawsze porównuje bieżącą sprzedaż do „pełnego” celu, ustalonego na cały rok, bez względu na to, jaki miesiąc wybrał użytkownik:
[Cel Roczny Stały] =
CALCULATE(
[Cel Roczny],
REMOVEFILTERS(Kalendarz)
)
[Realizacja % vs Cel Roczny Stały] =
DIVIDE([Suma Sprzedaży], [Cel Roczny Stały])
Efekt: kiedy filtrujesz tylko Q1, sprzedaż dotyczy Q1, ale cel w mianowniku nadal obejmuje pełen rok. Na wykresie widać więc, jak daleko zrealizowano roczny plan w danym kwartale. Dla osób oglądających raport to często pierwsze zderzenie z tym, że segment Rok/Miesiąc „nie działa” na wszystkie kolumny tak samo – ale to właśnie rezultat świadomego użycia REMOVEFILTERS.
Podobny schemat pojawia się przy:
- limitach budżetowych (np. miesięczny cap niezależny od wybranego produktu),
- docelowym poziomie marży (ta sama wartość referencyjna bez względu na filtr kategorii),
- benchmarkach rynkowych (np. średnia branżowa nieograniczona filtrami klienta).
Za każdym razem REMOVEFILTERS „oddkleja” część obliczenia od aktualnego widoku raportu. Dla kogoś, kto spodziewa się, że wszystkie miary zawsze reagują na te same segmenty, to źródło pozornych sprzeczności.
KEEPFILTERS – gdy filtry z miary mają być słabsze niż z raportu
Domyślnie filtry w CALCULATE nadpisują istniejące ograniczenia na tych samych kolumnach. To wygodne, ale czasem za mocne. Są sytuacje, w których filtr z miary ma jedynie „doprecyzować” wybór użytkownika, a nie go unieważnić. Tu pojawia się KEEPFILTERS.
Wyobraź sobie, że raport ma segment Kategoria Produktu, a Ty chcesz zbudować miarę, która zawsze liczy sprzedaż tylko produktów „Premium”, ale jeśli użytkownik zawęzi się do podzbioru kategorii, ten filtr ma nadal obowiązywać.
Przykład bez KEEPFILTERS:
[Sprzedaż Premium] =
CALCULATE(
[Suma Sprzedaży],
Produkty[Segment] = "Premium"
)
Jeśli użytkownik wybierze w segmencie Produkty[Segment] wartości „Standard” i „Premium”, powyższa miara zignoruje wybór i policzy wyłącznie „Premium”. Czasem jest to pożądane, ale jeśli chcesz, by miara szanowała ograniczenie użytkownika (np. tylko określone kategorie), dodaj KEEPFILTERS:
[Sprzedaż Premium (z poszanowaniem filtrów)] =
CALCULATE(
[Suma Sprzedaży],
KEEPFILTERS(Produkty[Segment] = "Premium")
)
W praktyce oznacza to:
- jeśli użytkownik nie wybierze żadnego segmentu – miara zwróci sprzedaż wszystkich produktów Premium,
- jeśli wybierze kilka segmentów, ale wśród nich jest „Premium” – miara policzy tylko Premium w ramach tego wyboru,
- jeśli wybór użytkownika wykluczy „Premium” (np. tylko „Standard”) – miara zwróci BLANK, bo przecięcie filtrów jest puste.
KEEPFILTERS nie wygląda spektakularnie, ale pomaga uniknąć wielu nieporozumień w raportach „samodzielnie” eksplorowanych przez biznes. Zamiast twardo „wyrywać” filtr z rąk użytkownika, dokładasz swój warunek jako kolejny poziom zawężenia.
VALUES – most między „tym co w kontekście” a argumentami CALCULATE
VALUES zwraca unikalny zestaw wartości z kolumny (lub kombinacji kolumn) w bieżącym kontekście filtra. Brzmi abstrakcyjnie, ale w praktyce VALUES często pomaga „przenieść” coś, co użytkownik wyklikał, do środka miary.
Klasyczny przypadek: raport ma segment Waluta, a Ty chcesz zbudować miarę, która przelicza sprzedaż na aktualnie wybraną walutę po stosownym kursie. Prosta miara może wyglądać tak:
[Sprzedaż bazowa] = SUM(Sprzedaż[Kwota_PLN])
[Sprzedaż w wybranej walucie] =
VAR WybranaWaluta = SELECTEDVALUE(Waluty[Waluta])
RETURN
CALCULATE(
[Sprzedaż bazowa] / MAX(Kursy[Kurs]),
VALUES(Waluty[Waluta])
)
VALUES w argumencie CALCULATE upewnia się, że obliczenie odbywa się dokładnie dla tego zestawu walut, który jest aktualnie w kontekście (zwykle jedna waluta z segmentu). Jeśli segmentu nie ma, albo użytkownik zaznaczy więcej niż jedną walutę, razem z SELECTEDVALUE otrzymasz albo konkretną walutę, albo BLANK – i łatwo możesz dodać prostą obsługę błędu.
Drugi, bardzo częsty scenariusz, to miary typu „liczba wybranych elementów” czy „etykieta kontekstu”. Przykład:
[Wybrane kraje] =
CONCATENATEX(
VALUES(Klienci[Kraj]),
Klienci[Kraj],
", "
)
Taka miara zwróci listę wszystkich krajów będących aktualnie w filtrze (z tabeli przestawnej, segmentów, filtrów raportu). Gdy ktoś porównuje dwie miary, które pozornie „patrzą” na ten sam zestaw danych, taka etykieta kontekstu potrafi szybko ujawnić różnice: inne kraje, inne lata, inne produkty biorą udział w obliczeniu.
Łączenie ALL, REMOVEFILTERS, KEEPFILTERS i VALUES w jednej miarze
W praktyce prawie zawsze występuje mieszanka kilku funkcji kontekstowych. To właśnie ich kombinacje dają wrażenie „magicznych” zachowań, gdy liczby zmieniają się w nieintuicyjny sposób po dodaniu kolumny do tabeli przestawnej.
Wyobraź sobie miarę: „udział sprzedaży produktu w całkowitej sprzedaży kategorii, ignorując filtry na produkt, ale szanując filtry użytkownika na region i rok”. Jedna z możliwych implementacji:
[Sprzedaż Produktu] = [Suma Sprzedaży]
[Sprzedaż Kategorii] =
CALCULATE(
[Suma Sprzedaży],
REMOVEFILTERS(Produkty[Produkt]),
KEEPFILTERS(VALUES(Produkty[Kategoria]))
)
[% Udział w Kategorii] =
DIVIDE([Sprzedaż Produktu], [Sprzedaż Kategorii])
Co tu się dzieje krok po kroku:
REMOVEFILTERS(Produkty[Produkt])– usuwa filtry na poziomie poszczególnych produktów, żeby policzyć sumę po całej kategorii,VALUES(Produkty[Kategoria])– pobiera bieżącą kategorię z kontekstu (np. „Laptopy”),KEEPFILTERS(...)– dba o to, żeby filtr na kategorię (pochodzący z bieżącego wiersza lub kolumny kategorii w tabeli przestawnej) nie został przypadkiem nadpisany przez cokolwiek innego.
Użytkownik może dowolnie ograniczać raport po regionie, roku, kanale sprzedaży – te filtry przechodzą dalej. Miara ignoruje jednak przełączenia na poziomie pojedynczych produktów, dbając o to, by mianownik zawsze odnosił się do całej kategorii, a nie do pojedynczej pozycji.
Właśnie w takich sytuacjach często pojawia się zdanie „przecież wybrałem produkt X, a ta kolumna pokazuje coś większego niż sprzedaż X”. Z punktu widzenia DAX-a wszystko jest spójne: część miary używa innego, świadomie zmodyfikowanego kontekstu.
Jak czytać miary, które „same” zmieniają kontekst
Najtrudniejszy moment przy pracy z cudzym modelem to zrozumienie, dlaczego konkretna miara reaguje inaczej niż inne. Tu pomaga kilka prostych kroków, które można stosować niemal odruchowo:
- Znajdź każde wywołanie CALCULATE. To punkty, w których miara może zmienić lub rozszerzyć kontekst filtra.
- Sprawdź, czy w argumentach jest ALL lub REMOVEFILTERS. Jeśli tak, wypisz sobie, z których kolumn lub tabel zdejmowany jest filtr – to one będą „ignorowały” segmenty.
- Poszukaj KEEPFILTERS i VALUES. Zwykle oznaczają one, że miara szanuje bieżący kontekst, ale nakłada dodatkowe warunki lub przenosi aktualny wybór (np. kategorię, walutę) do innego fragmentu obliczenia.
- Porównaj to z faktycznymi segmentami na raporcie. Jeśli segment jest ustawiony na kolumnę, którą ALL lub REMOVEFILTERS wycina, różnice w liczbach są wytłumaczone.
To podejście nie wymaga znajomości każdego niuansu DAX-a. Wystarczy kilka minut spokojnej analizy, żeby zobaczyć, że miara „nie zwariowała” – po prostu w środku stosuje inne reguły gry niż standardowe sumowanie.
Segmenty, filtr raportu i miary „odporne” na wybory użytkownika
Spore napięcie pojawia się wtedy, gdy część miar reaguje na segmenty, a część pozostaje „niewzruszona”. Użytkownik ma poczucie, że raport kłamie, bo dwie kolumny obok siebie odpowiadają na inne pytanie. Zwykle nie jest to zła wola twórcy modelu, tylko świadome rozdzielenie dwóch typów miar:
- miary wrażliwe – mają liczyć dokładnie to, co widać na ekranie, w pełni podporządkowane segmentom i polom przestawnym,
- miary referencyjne – mają opisywać „tło”: benchmark, cel ogólny, docelowy poziom KPI, średnią długoterminową itd., najczęściej z częściowo oczyszczonym kontekstem.
Jeśli tworzysz lub analizujesz takie miary, pomocne bywają proste standardy nazewnicze, np.:
- dodanie sufiksu „(stały cel)” lub „(ignoruje filtry czasu)” do nazwy miary,
- stosowanie komentarza w definicji DAX (krótka notka, które filtry są ignorowane),
- wyróżnienie wizualne na raporcie (np. oddzielna karta KPI dla celu globalnego).
Dzięki temu mniej osób oczekuje, że każda liczba będzie się ruszać wraz z każdym segmentem. Część liczb ma być właśnie „punktem odniesienia”, a nie ruchomą częścią raportu.
Jak świadomie wykorzystywać „magiczne” zmiany miar
Kiedy już wiesz, skąd biorą się różnice, możesz traktować je nie jako problem, ale jako narzędzie. Kilka krótkich przykładów zastosowań, które często robią wrażenie na odbiorcach raportu:
- Porównania do stałego benchmarku – miary typu
[Wynik vs Średnia 3-lata], gdzie CALCULATE z REMOVEFILTERS na czasie bierze stałe okno historyczne, niezależne od bieżącego widoku. - Miary „co by było, gdyby” – sprzedaż liczona przy założeniu stałego miksu produktowego, mimo że użytkownik filtruje tylko część portfolio; ALL/REMOVEFILTERS na produktach + KEEPFILTERS na kilku kluczowych segmentach.
- Analizy udziałów – udział klienta w sprzedaży całej branży, gdzie Twoja sprzedaż liczy się w pełnym kontekście, a „cała branża” używa ALL na tabeli Klienci, tworząc pełen obraz niezależnie od bieżącego filtra klienta.
W każdym z tych scenariuszy segmenty i pola w raporcie nadal są ważne, ale nie dla wszystkich miar w identyczny sposób. Kluczem jest świadome projektowanie kontekstu: które filtry są „ruchome”, a które stają się częścią definicji miary, niepodlegającą interakcji użytkownika.
Najczęściej zadawane pytania (FAQ)
Dlaczego ta sama miara DAX pokazuje różne wyniki w różnych tabelach przestawnych?
Miara DAX nigdy nie liczy „w próżni”. Za każdym razem działa w konkretnym kontekście filtra – czyli na podzbiorze danych wyciętym przez pola w wierszach/kolumnach przestawnej, segmenty, filtry raportu i relacje między tabelami. Gdy zmienia się ten zestaw filtrów, zmienia się też pytanie, na które odpowiada miara, a więc i sama liczba.
Przykład: ta sama formuła [Suma Sprzedaży] = SUM(Sprzedaż[Kwota]) w przestawnej bez pól w wierszach poda sprzedaż „ze wszystkich lat i krajów”, ale po dodaniu pola Rok i segmentu Kraj odpowie już na pytanie: „jaka jest suma sprzedaży w danym roku i kraju”. Formuła jest ta sama, zmienia się tylko kontekst.
Dlaczego suma w arkuszu Excela różni się od sumy miary w Power Pivot?
Klasyczna funkcja arkuszowa =SUMA(Kwota) liczy wszystko, co jest w zakresie – często także ukryte wiersze – i nie uwzględnia relacji ani segmentów. Działa na płaskiej liście komórek, bez świadomości modelu danych.
Miara DAX, np. SUM(Sprzedaż[Kwota]), pracuje w modelu danych. Oznacza to, że „widzi” tylko te wiersze tabeli faktów, które przejdą przez filtry z tabel wymiarów, segmentów i filtrów raportu. Jeśli w przestawnej masz ustawiony filtr na konkretny rok, to miara zliczy wyłącznie sprzedaż z tego roku, podczas gdy formuła arkuszowa nadal sumuje całą kolumnę.
Co dokładnie robi segment (slicer) w Power Pivot i jak wpływa na miary?
Segment nie zmienia formuły miary ani jej definicji w DAX. Dodaje po prostu filtr do jednej z tabel w modelu danych (zwykle do tabeli wymiaru), a ten filtr propaguje się relacjami do tabel faktów. Efekt jest taki, że miara liczy się na węższym zestawie wierszy.
Jeśli masz segment Rok pochodzący z tabeli Kalendarz, to wybór 2023 zawęża Kalendarz do jednego roku. Ten filtr przechodzi po relacji do Sprzedaż i miara SUM(Sprzedaż[Kwota]) liczy tylko sprzedaż z 2023. Po dodaniu segmentu Kraj = „Polska” liczony jest już tylko podzbiór: rok 2023 i kraj Polska.
Czym jest kontekst filtra i kontekst wiersza w DAX w prostych słowach?
Kontekst filtra to zestaw warunków, które określają, na jakich wierszach danych ma się wykonać miara. Tworzą go m.in. pola wrzucone do wierszy/kolumn przestawnej, segmenty, filtry raportu i relacje. Gdy patrzysz na jedną komórkę w przestawnej, to tak naprawdę patrzysz na wynik miary policzonej na „przyciętej” tabeli faktów.
Kontekst wiersza dotyczy pojedynczego wiersza tabeli (np. podczas obliczeń w kolumnie obliczeniowej albo wewnątrz iteratorów typu SUMX). Wtedy formuła „wie”, w którym konkretnym wierszu jest i może odwoływać się do innych kolumn tego samego wiersza. Miary zwykle działają w kontekście filtra, a nie wiersza – dlatego tak mocno reagują na segmenty i filtry.
Dlaczego moja miara DAX czasem zwraca BLANK() albo „puste”, zamiast zera?
BLANK() pojawia się wtedy, gdy w aktualnym kontekście filtra nie ma żadnych wierszy, które spełniają wszystkie warunki, albo gdy wynik obliczeń jest logicznie „brak danych”. To zwykle nie jest błąd, tylko konsekwencja tego, że wszystkie filtry razem wzięte „wykasowały” dane dla danej kombinacji pól.
Typowy przykład: w tabeli przestawnej zestawiasz konkretnego klienta z produktem, którego nigdy nie kupił. Dla takiego połączenia nie ma żadnych wierszy w tabeli Sprzedaż, więc miara sumująca sprzedaż zwróci BLANK(). W wielu przypadkach oznacza to, że model działa poprawnie, a nie że coś „zniknęło”.
Dlaczego segment z tabeli faktów potrafi dawać „dziwne” wyniki w modelu danych?
Standardowo relacje w modelu danych są jednokierunkowe: filtr z tabeli wymiaru przechodzi do tabeli faktów, ale nie w drugą stronę. Gdy użyjesz kolumny z tabeli faktów jako segmentu, filtr zatrzymuje się często właśnie na tej tabeli i nie wraca do wymiarów. To może powodować rezultaty, które intuicyjnie wydają się błędne.
Bezpieczniejszym podejściem jest budowanie segmentów na tabelach wymiarów (Kalendarz, Produkty, Klienci, Regiony). Wtedy filtr płynie z wymiaru do faktu w przewidywalny sposób, a miary zachowują się spójnie w całym raporcie.
Jak sprawdzić, dlaczego miara w konkretnej komórce ma taką wartość?
Najprostszy krok to zadać sobie precyzyjne pytanie: „Jakie filtry działają w tej komórce?”. Można to zrobić „na piechotę”, patrząc na: pola w wierszach i kolumnach, włączone segmenty, filtry raportu oraz to, z których tabel pochodzą te pola. Często już to pozwala zobaczyć, że liczba jest wynikiem bardzo zawężonego kontekstu.
W praktyce pomagają też narzędzia DAX, np. miary pomocnicze liczące COUNTROWS wybranych tabel, funkcje typu VALUES czy ALL, a także tymczasowe wyłączanie niektórych filtrów. Dzięki temu można krok po kroku zawęzić problem i zrozumieć, które filtry najbardziej wpływają na wynik.
Najważniejsze wnioski
- Miary DAX nigdy nie liczą „w próżni” – każda wartość jest odpowiedzią na pytanie zadane w konkretnym kontekście filtra, który wynika z tabeli przestawnej, segmentów i relacji w modelu.
- Różnica między SUMA w arkuszu Excela a SUM w miarze DAX bierze się z filtrowania: formuła arkuszowa zlicza po prostu wszystkie widoczne komórki, a miara DAX działa tylko na wierszach dopuszczonych przez bieżący kontekst filtra.
- Segmenty (Slicery) nie zmieniają samej formuły miary, lecz zawężają zbiór wierszy, na którym ta miara się oblicza – stąd wrażenie, że „ta sama” miara nagle daje inne liczby po kliknięciu filtra.
- Gwałtowne spadki wartości lub wyniki BLANK() zwykle nie oznaczają błędu DAX, tylko sytuację, w której po nałożeniu wszystkich filtrów w danej komórce nie zostaje żaden pasujący wiersz danych.
- Kluczem do opanowania „magicznych” zmian wyników jest nawyk zadawania pytania: „Jaki dokładnie kontekst filtra obowiązuje dla tej komórki?”, zamiast szukania błędów w samych formułach.
- Model danych różni się od zwykłej tabeli przestawnej tym, że opiera się na wielu tabelach, relacjach i propagacji filtrów – dlatego tabela przestawna staje się w praktyce interfejsem do zapytań na bazie danych, a nie prostą sumą komórek.
Źródła informacji
- The Definitive Guide to DAX: Business intelligence with Microsoft Excel, SQL Server Analysis Services, and Power BI. Microsoft Press (2020) – Kontekst filtrowania, miary, przepływ filtrów w modelu danych
- Analyzing Data with Power BI and Power Pivot for Excel. Microsoft Press (2017) – Model danych w Excelu, relacje, tabele faktów i wymiarów
- Microsoft Learn: DAX in Power BI, Power Pivot, and Analysis Services. Microsoft – Podstawy języka DAX, miary, kontekst filtra i wiersza






