Blog JSystems - uwalniamy wiedzę!
Blog JSystems - uwalniamy wiedzę!
Power BI - DAX liczy, ale nie to, czego oczekujesz
Kolumna obliczeniowa z CALCULATE liczy coś innego niż bez niej - przejście kontekstu
Przejście kontekstu w DAX zaskakuje każdego, kto pierwszy raz dopisuje do tabeli kolumnę obliczeniową z sumą: formuła bez CALCULATE pokazuje w każdym wierszu sprzedaż całej firmy, a z CALCULATE sprzedaż jednego sklepu. Ten sam mechanizm decyduje o wyniku SUMX, FILTER i AVERAGEX z miarą w środku. Pokazujemy na modelu Nordvelli, co dokładnie robi CALCULATE w kontekście wiersza, gdzie to pomaga, a gdzie tylko kosztuje.
W tabeli DimSklepy są dwie kolumny obliczeniowe z kursu. Sprzedaż sklepu (zła) = SUM(FaktSprzedaz[WartoscNetto]) ma w każdym z 15 wierszy 467 775 009,17 zł, czyli sprzedaż całej sieci. Sprzedaż sklepu = CALCULATE(SUM(FaktSprzedaz[WartoscNetto])) daje kwotę sklepu: Warszawa Centrum 34 740 655,15 zł, Warszawa Mokotów 25 320 459,78 zł, Kraków Stare Miasto 31 545 739,77 zł. Zła kolumna przeciągnięta do wizualizacji z regionami sumuje się do 1 871 100 036,68 zł dla regionu Centrum, czyli do czterokrotności sprzedaży sieci, bo region ma cztery sklepy.
Ten sam objaw pojawia się w miarach z iteratorem. SUMX(DimSklepy, SUM(FaktSprzedaz[WartoscNetto])) zwraca 7 016 625 137,55 zł, piętnaście razy sprzedaż sieci, a FILTER(DimSklepy, SUM(FaktSprzedaz[WartoscNetto]) > 30000000) przepuszcza wszystkie 15 sklepów, choć próg 30 mln zł przekracza tylko pięć. Kolumna SUM(FaktSprzedaz[WartoscNetto]) w tabeli faktów ma tę samą kwotę we wszystkich 108 675 wierszach.

Zobacz też: Szkolenie Zaawansowany DAX w Power BI
DAX ma dwa rodzaje kontekstu. Kontekst wiersza to znajomość jednego, bieżącego wiersza, który mają kolumny obliczeniowe i iteratory, takie jak SUMX czy FILTER. Kontekst filtra to zestaw warunków ograniczających dane, który tworzą wiersze wizualizacji, fragmentatory i CALCULATE. Funkcje agregujące, na przykład SUM, widzą tylko kontekst filtra. W kolumnie obliczeniowej ten kontekst jest pusty, więc SUM liczy całą tabelę, niezależnie od tego, w którym wierszu się znajduje.
CALCULATE wywołane w kontekście wiersza wykonuje przejście kontekstu: zamienia bieżący wiersz na filtr każdej kolumny tej tabeli. W DimSklepy filtr obejmuje między innymi SklepID, a relacja jeden do wielu przenosi go do FaktSprzedaz, więc suma dotyczy jednego sklepu. Według dokumentacji Microsoft odwołanie do miary w kontekście wiersza wykonuje przejście kontekstu automatycznie. Dzieje się tak, bo każda miara jest wewnętrznie owinięta w niejawne CALCULATE. Dlatego SUMX(DimSklepy, [Łączna sprzedaż]) daje 467 775 009,17 zł, a FILTER(DimSklepy, [Łączna sprzedaż] > 30000000) zostawia pięć sklepów: Warszawa Centrum, Kraków Stare Miasto, Wrocław, Katowice i Nordvella Online.
W tabeli faktów przejście kontekstu filtruje kolumny tego samego wiersza. FaktSprzedaz ma unikatowy SprzedazID (108 675 wartości na 108 675 wierszy), więc CALCULATE(SUM(FaktSprzedaz[WartoscNetto])) zwraca dokładnie wartość wiersza. Druga taka kolumna obok kończy się komunikatem „Wykryto zależność cykliczną” (w angielskiej wersji: „A circular dependency was detected”), co opisujemy w poście o zależności cyklicznej w kolumnach obliczeniowych.
DimSklepy) wymaga przejścia kontekstu. Suma grupy w tej samej tabeli faktów (sprzedaż sklepu przy każdej transakcji) wymaga przejścia kontekstu z ograniczeniem do kolumn grupy.Sprzedaż sklepu. Liczba transakcji przez RELATEDTABLE to 8145 dla Warszawy Centrum i 6423 dla Gdańska, a COUNTROWS(FaktSprzedaz) bez niej daje 108 675 w każdym wierszu.Sprzedaż sklepu RT = SUMX ( RELATEDTABLE ( FaktSprzedaz ), FaktSprzedaz[WartoscNetto] ) Transakcje sklepu = COUNTROWS ( RELATEDTABLE ( FaktSprzedaz ) )
Średnia sprzedaż sklepu = AVERAGEX ( DimSklepy, [Łączna sprzedaż] ) Największa sprzedaż sklepu = MAXX ( DimSklepy, [Łączna sprzedaż] )
CALCULATE(SUM(FaktSprzedaz[WartoscNetto])) w FaktSprzedaz nie różni się od WartoscNetto w żadnym ze 108 675 wierszy, a formuła z przejściem kontekstu liczy się osobno dla każdego wiersza przy każdym odświeżeniu modelu. Użyj kolumny bezpośrednio, a obliczenia na wierszu zapisuj zwykłymi operatorami.-- w FaktSprzedaz, przez wymiar (15 obliczeń w DimSklepy)
Sprzedaż sklepu z wymiaru =
RELATED ( DimSklepy[Sprzedaż sklepu] )
-- w FaktSprzedaz, przez ALLEXCEPT (obliczenie w każdym wierszu)
Sprzedaż sklepu w wierszu =
CALCULATE (
SUM ( FaktSprzedaz[WartoscNetto] ),
ALLEXCEPT ( FaktSprzedaz, FaktSprzedaz[SklepID] )
)Sprawdź kolumnę na kilku wierszach i na sumie. Po poprawce wartości różnią się między sklepami, a ich suma zgadza się z miarą: na modelu Nordvelli SUMX(DimSklepy, CALCULATE(SUM(FaktSprzedaz[WartoscNetto]))) daje 467 775 009,17 zł, tyle co [Łączna sprzedaż], a kolumna z liczbą transakcji przez RELATEDTABLE sumuje się do 108 675, czyli do liczby wierszy FaktSprzedaz. Gdy wszystkie wiersze mają tę samą wartość albo suma kolumny jest wielokrotnością miary, w formule brakuje przejścia kontekstu.
Przy każdej kolumnie obliczeniowej z agregacją sprawdź dwie rzeczy: czy formuła ma CALCULATE albo RELATEDTABLE i czy tabela jest po stronie jeden relacji z faktami. W tabelach faktów trzymaj tylko kolumny liczone z własnego wiersza albo pobrane przez RELATED.
Zachowanie programu sprawdziliśmy w Power BI Desktop 2.157 (wydanie z sierpnia 2026 r.) z polskim interfejsem, a przykłady na modelu sieci Nordvella z bezpłatnego kursu Power BI. Microsoft wydaje nową wersję Power BI Desktop co miesiąc, więc nazwy przycisków i limity usługi mogą się zmieniać. Aktualne wartości podaje dokumentacja Microsoft Learn.
Wróć do listy: 131 najczęstszych pytań i problemów związanych z Power BI
Komentarze (0)
Brak komentarzy...