Gdzie w Power Query pojawiają się wyrażenia if i po co ich używać
Kluczowe miejsca użycia if w Power Query
Wyrażenia if w języku M są rdzeniem większości bardziej zaawansowanych transformacji w Power Query. Pojawiają się w kilku powtarzalnych miejscach pracy z zapytaniami:
- Kolumny niestandardowe – ręcznie tworzone kolumny z warunkiem, np. klasyfikacja transakcji, nadawanie etykiet, flagi logiczne.
- Kolumny warunkowe – generowane z poziomu interfejsu (przycisk „Kolumna warunkowa”), ale w tle zawsze powstaje instrukcja
if ... then ... else .... - Kroki filtrowania – filtr „Zachowaj wiersze, które spełniają warunek” przekłada się na warunki logiczne, często oparte na
andior. - Kroki w Edytorze Zaawansowanym – samodzielnie dopisywane warunki w kodzie M, np. w definicji
Table.AddColumnlubTable.SelectRows. - Parametry i logika sterująca – parametry użytkownika (np. data od–do) wykorzystywane w wyrażeniach if, aby przełączać scenariusze przetwarzania danych.
Za każdym razem chodzi o to samo: przełożyć reguły biznesowe na kod. Gdy księgowy mówi „transakcje powyżej kwoty X potraktuj inaczej”, w Power Query staje się to wyrażeniem if w języku M. Kod staje się dokumentacją tych reguł – pod warunkiem, że if jest napisany czytelnie.
If jako zapis reguł biznesowych w transformacjach
Power Query służy do przygotowania danych pod dalszą analizę. Na etapie transformacji użytkownik podejmuje drobne decyzje: który wiersz zachować, jak nazwać kategorię, jak obsłużyć wartości null lub błędy. W praktyce są to właśnie reguły biznesowe, tyle że opisane w języku M.
Typowe zastosowania wyrażeń if w tym kontekście to m.in.:
- kwalifikowanie transakcji jako „koszt”, „przychód”, „przeniesienie” na podstawie opisu i kwoty,
- definiowanie progów rabatowych zależnych od wartości zamówienia,
- ustawianie flagi „VIP” w zależności od obrotu i czasu współpracy z klientem,
- wyłączanie z analizy wierszy, które nie spełniają wymogów raportowych,
- sterowanie przepływem – np. inne źródło danych, jeśli parametr
Środowisko= „Test”, a inne, gdy „Prod”.
Im czytelniej zostaną napisane warunki logiczne w kolumnach obliczeniowych, tym łatwiej po kilku miesiącach odtworzyć logikę, skorygować ją lub włączyć do niej nową regułę. Dlatego kwestia czytelności wyrażeń if nie jest kosmetyką, tylko realnym elementem utrzymania raportów.
Różnica między klikaniem a świadomym pisaniem if w M
Power Query oferuje wygodne kreatory: kolumny warunkowe, filtrowanie z menu, przyciski wstążki. Te narzędzia generują kod M, który można obejrzeć w Edytorze Zaawansowanym. Dla prostych scenariuszy kliknięcie kilku opcji jest najszybsze.
Przy bardziej złożonych warunkach zaczyna jednak być widoczna różnica między podejściem „klikam” a „świadomie piszę if w języku M”:
- kreator dodaje kolejne warunki sekwencyjnie, zwykle generując długie, zagnieżdżone if, które trudno czytać,
- warunki są rozdzielone na wiele kroków, zamiast być zebrane w jednej, logicznie ułożonej instrukcji,
- brakuje komentarzy i czytelnego nazewnictwa kroków,
- zmiana kolejności lub logiki wymaga przechodzenia po wielu krokach i kreatorach.
Świadome pisanie if w Edytorze Zaawansowanym pozwala:
- zadbać o czytelne grupowanie warunków nawiasami,
- stosować funkcje pomocnicze (np. wydzielenie jednej większej logiki do osobnej funkcji),
- krócej i czytelniej zapisać to, co kreator wygenerowałby na kilku ekranach,
- łatwiej debugować wyrażenia if w Edytorze Zaawansowanym – testować fragmenty, dodawać tymczasowe kolumny pomocnicze.
Przykład: klasyfikacja transakcji na „przychód” i „koszt”
W prostym scenariuszu użytkownik ma kolumnę Kwota, gdzie wartości dodatnie oznaczają przychody, a ujemne – koszty. Jeśli w kreatorze kolumny warunkowej wybierze logikę „Jeśli Kwota >= 0, to 'Przychód’, w przeciwnym razie 'Koszt’”, Power Query wygeneruje kod w tym stylu:
= Table.AddColumn(
PoprzedniKrok,
"Typ transakcji",
each if [Kwota] >= 0 then "Przychód" else "Koszt"
)
To prosty przykład, ale dobrze pokazuje, co faktycznie robi wyrażenie if w M: ocenia warunek logiczny i zwraca jedną z dwóch wartości. Taka kolumna czytelnie zakodowuje regułę: „Kwoty nieujemne to przychód, pozostałe – koszt”. Jeżeli kiedyś definicja się zmieni (np. 0 traktować osobno), wystarczy korekta jednego warunku.
Podstawowa składnia if w języku M – co faktycznie się tam dzieje
Obowiązkowa konstrukcja if … then … else …
W języku M instrukcja warunkowa ma ściśle określoną składnię:
if <warunek logiczny> then <wartość gdy prawda> else <wartość gdy fałsz>
Kluczowy fakt: część else jest obowiązkowa. W przeciwieństwie do wielu języków programowania, w M nie istnieje „gołe” if bez gałęzi else. Próba zapisania:
if [Kwota] > 0 then "Przychód"
zakończy się błędem składni. M oczekuje pełnego trójczłonu if-then-else. Jeśli użytkownik chce „nic nie robić”, może explicite zwracać np. null lub oryginalną wartość kolumny:
if [Kwota] > 0 then "Przychód" else null
albo:
if [Kwota] > 0 then [Kwota] else [Kwota]
Drugi przykład jest logicznie zbędny, ale poprawny składniowo – przydatny w sytuacjach, gdy tymczasowo testuje się warunek w strukturze kodu.
Typ logiczny w M i wynik porównań
Warunek wewnątrz if musi zwrócić wartość typu logical (true/false). Typ logiczny w M powstaje najczęściej w dwóch przypadkach:
- jako wynik porównania (np.
[Kwota] > 0,[Status] = "Aktywny"), - jako wynik funkcji, która zwraca logic (np.
Text.Contains,Value.Is, własne funkcje).
Wyrażenie if nie przyjmuje liczby ani tekstu jako warunku – każda część poprzedzająca then musi być logiczna. Przykłady poprawnych fragmentów:
if [Kwota] >= 1000 then "Duża" else "Mała"
if Text.Contains([Opis], "faktura") then "Faktura" else "Inne"
if [Data] >= #date(2023, 1, 1) then "Nowy rok" else "Stary rok"
Warto też odróżnić dwa poziomy logiki:
- prosty warunek – pojedyncze porównanie, np.
[Kwota] < 0, - złożony warunek – połączenie kilku prostych warunków przy użyciu
and,or,not.
W obu przypadkach wynik musi być true/false, aby instrukcja if mogła zdecydować, którą gałąź wykonać.
Proste porównania liczb, tekstów i dat
Do budowania warunków M wykorzystuje standardowe operatory porównania:
=– równe,<>– różne,>– większe niż,<– mniejsze niż,>=– większe lub równe,<=– mniejsze lub równe.
Przykłady prostych porównań dla różnych typów:
// liczby
[Kwota] > 0
[Rabatt] <= 0.1
// teksty (w M porównanie jest czułe na wielkość liter)
[Status] = "Aktywny"
[Kraj] <> "Polska"
// daty
[DataSprzedaży] >= #date(2024, 1, 1)
[DataDokumentu] < #date(2023, 7, 1)
Porównania tekstów są domyślnie case-sensitive. Oznacza to, że "Polska" <> "polska", a warunki typu [Status] = "aktywny" nie złapią wartości „Aktywny”, jeśli dane nie są uprzednio ujednolicone. Jedną z praktyk poprawiających czytelność jest wcześniejsze użycie Text.Upper lub Text.Lower i porównywanie już przetworzonego tekstu.
Porównanie wartości vs porównanie odwołań (wzmianka)
W codziennej pracy z Power Query if operuje głównie na prostych typach: liczbach, tekstach, datach, wartościach logicznych i null. Język M pozwala jednak porównywać także bardziej złożone struktury, takie jak rekordy czy tabele.
Standardowe porównanie = dla rekordów i tabel może jednak nie zachowywać się tak, jak użytkownik intuicyjnie oczekuje, dlatego dla bardziej złożonych typów przewidziano funkcje, np.:
Record.Equals(record1, record2)Table.Equals(table1, table2)
W praktyce raportowej takie porównania są rzadkie. Najczęściej warunki if opierają się na prostych polach tabeli. Świadomość istnienia tych funkcji jest przydatna głównie przy pisaniu bardziej zaawansowanych funkcji w M, np. do testów jakości danych.

If w kreatorze kolumn niestandardowych vs Edytor Zaawansowany – dwa widoki tej samej logiki
Jak Power Query generuje if z interfejsu
Przyciski „Kolumna warunkowa” i „Kolumna niestandardowa” to dwa podstawowe narzędzia użytkownika, który nie chce od razu zaglądać do kodu. Oba kończą się jednak tym samym: Power Query generuje w tle wyrażenie if w języku M i dodaje krok Table.AddColumn do sekwencji transformacji.
Przykład z kreatora „Kolumna warunkowa”:
- Warunek: Jeśli
Kwota> 1000, to „Duże”, w przeciwnym razie „Pozostałe”.
Wygenerowany kod będzie wyglądał podobnie do:
= Table.AddColumn(
#"Poprzedni krok",
"Segment",
each if [Kwota] > 1000 then "Duże" else "Pozostałe"
)
Jeżeli użytkownik doda w kreatorze więcej niż jeden warunek (dragnięcie w dół listy reguł), narzędzie zbuduje odpowiednią drabinkę zagnieżdżonych if – każdy kolejny warunek stanie się kolejnym else if zakodowanym przez odpowiednie zagnieżdżenie.
Odczytywanie i modyfikacja kodu w Edytorze Zaawansowanym
Każdy krok utworzony w ten sposób można obejrzeć w Edytorze Zaawansowanym. To tutaj staje się jasne, jak dokładnie wygląda warunek i jak jest zdefiniowana kolumna.
Przykładowo, po utworzeniu kilku warunków w kreatorze, kod może wyglądać tak:
= Table.AddColumn(
#"Poprzedni krok",
"Segment",
each if [Kwota] >= 10000 then "Strategiczny"
else if [Kwota] >= 5000 then "Duży"
else if [Kwota] >= 1000 then "Średni"
else "Mały"
)
W Edytorze Zaawansowanym można teraz:
- zmienić nazwy progów bez przechodzenia przez kreator,
- dodać nowy warunek ręcznie (np. dla wartości ujemnych),
- dodać komentarz nad krokiem wyjaśniający logikę,
- rozbić skomplikowaną logikę na dwie kolumny pomocnicze, aby zwiększyć czytelność.
Dla osób, które zaczynają od interfejsu, wgląd do Edytora Zaawansowanego jest dobrą okazją, by zobaczyć, jak klikanie przekłada się na składnię if w M.
Zalety i ograniczenia kreatora kolumn warunkowych
Kreator ma kilka oczywistych zalet:
Jak daleko „dowiezie” sam kreator, a gdzie zaczyna się Edytor Zaawansowany
Kilkukrotne kliknięcie w „Kolumna warunkowa” rozwiązuje proste scenariusze. Problem zaczyna się przy logice, która musi reagować na więcej niż jedno źródło danych lub kilka wyjątków biznesowych.
Typowe ograniczenia kreatora:
- brak warunków złożonych – interfejs pozwala wskazać jedno pole i jeden operator na regułę; trudno w nim wyrazić „Kwota > 0 i Status = 'Aktywny’”,
- brak kontroli nad kolejnością ewaluacji – drabinka warunków jest generowana automatycznie; im więcej reguł, tym trudniej przewidzieć, który „if” zadziała pierwszy bez spojrzenia w kod,
- brak prostego kopiuj–wklej logiki między zapytaniami – przenoszenie kolumny warunkowej do innej tabeli wymaga powtórzenia klikania lub wejścia w M.
Edytor Zaawansowany otwiera kilka dodatkowych możliwości:
- łączenie warunków przy użyciu
and,or,not, - wyciąganie części wspólnej warunku do osobnego kroku lub kolumny,
- komentowanie poszczególnych gałęzi if (np.
// wyjątek: transakcje archiwalne), - szybka korekta progów lub wartości tekstowych bez przebijania się przez okna kreatora.
Co wiemy na tym etapie? Że oba narzędzia operują na tej samej konstrukcji if, ale w różnej skali kontroli. Kreator przyspiesza start, Edytor pozwala utrzymać porządek w bardziej rozbudowanych transformacjach.
Warunki logiczne krok po kroku: liczby, teksty, daty, wartości null
Warunki dla liczb – progi, zakresy i granice
W danych raportowych liczby zwykle klasyfikuje się według progów lub zakresów. Konstrukcja if dobrze oddaje takie reguły, pod warunkiem, że granice są opisane jednoznacznie.
Klasyfikacja prostego progu:
if [Kwota] >= 0 then "Przychód" else "Koszt"
Dla zakresów pojawia się pytanie kontrolne: czy granica ma być dolna, górna, czy obie w tym samym przedziale? Przykładowa segmentacja:
if [Kwota] < 0 then "Ujemna"
else if [Kwota] < 1000 then "Mała" // od 0 (włącznie) do < 1000
else if [Kwota] < 10000 then "Średnia" // od 1000 (włącznie) do < 10000
else "Duża" // od 10000 wzwyż
Warunki oparte na zakresach stają się czytelniejsze, gdy linie są łamane po then, a komentarze wskazują dokładny przedział liczbowy.
Warunki dla tekstów – dopasowania ścisłe i „zawiera”
Porównania tekstowe sprowadzają się do dwóch pytań: czy szukamy dokładnej wartości pola, czy fragmentu opisu.
Dopasowanie dokładne – przy polach słownikowych, takich jak status czy typ dokumentu:
if [Status] = "Aktywny" then "Ujęty" else "Wyłączony"
Gdy źródło danych jest niespójne (np. „aktywny”, „Aktywny”, „AKTYWNY”), bezpieczniej ujednolicić tekst przed porównaniem:
if Text.Upper([Status]) = "AKTYWNY" then "Ujęty" else "Wyłączony"
Dopasowanie częściowe – przy opisach, tytułach czy komentarzach. Tutaj przydaje się funkcja Text.Contains zwracająca wartość logiczną:
if Text.Contains(Text.Lower([Opis]), "faktura")
then "Faktura"
else "Inne"
Użycie Text.Lower lub Text.Upper przed Text.Contains niweluje różnice w wielkości liter i upraszcza późniejsze warunki.
Warunki dla dat – przedziały czasowe i „do końca dnia”
Daty w M są pełnoprawnym typem i można je porównywać jak liczby. Różnica dotyczy czytelności: surowe literały #date(2024, 1, 1) mało komu kojarzą się od razu z początkiem roku obrachunkowego.
Klasyfikacja względem konkretnej daty:
if [Data] < #date(2023, 1, 1) then "Przed 2023"
else "2023 i później"
Jeśli logika ma być powiązana z bieżąca datą, częściej stosuje się funkcje systemowe:
let
DzisiejszaData = Date.From(DateTime.LocalNow()),
Wynik = Table.AddColumn(
#"Poprzedni krok",
"Okres",
each if [Data] <= DzisiejszaData then "Zaksięgowana" else "Przyszła"
)
in
Wynik
Wprowadzenie nazwanego kroku DzisiejszaData porządkuje myślenie o warunku i ułatwia późniejszą korektę (np. podmianę na „koniec poprzedniego miesiąca”).
Null w warunkach – osobna kategoria, nie „pusta wartość”
null w M to nie jest zero ani pusty tekst, lecz osobny typ oznaczający brak wartości. Ma to kilka praktycznych konsekwencji.
Po pierwsze, porównanie [Kolumna] = null nie zadziała tak, jak sugeruje intuicja użytkownika Excela. Aby sprawdzić, czy wartość jest pusta, trzeba użyć:
if [Kolumna] = null then "Puste" else "Niepuste" // składniowo poprawne,
// ale słabo odróżnialne
lub jawnej funkcji:
if Value.Is([Kolumna], type null) then "Puste" else "Niepuste"
Jeszcze czytelniejsze będą dwa odrębne warunki:
if [Kolumna] = null then "Brak danych"
else if [Kolumna] = "" then "Pusty tekst"
else "Wypełnione"
W danych raportowych często trzeba osobno obsłużyć brak wartości, pusty ciąg znaków i realne dane – po to, by nie mieszać technicznego braku z biznesowym „0” lub „N/D”.
Mieszanie typów w jednym if – kiedy pojawia się problem
Gałęzie then i else w M powinny zwracać wartości tego samego typu, inaczej silnik będzie próbował dobrać typ nadrzędny lub zgłosi błąd konwersji.
Przykład potencjalnego kłopotu:
if [Kwota] > 0 then [Kwota] else "Brak kwoty"
W jednym przypadku zwracana jest liczba, w drugim tekst. Kolumna będzie mieć typ „any” i może sprawiać trudność przy dalszych obliczeniach. Bardziej uporządkowany wariant to rozdzielenie logiki na dwie kolumny:
// kolumna liczbowa
if [Kwota] > 0 then [Kwota] else null
// kolumna opisowa
if [Kwota] > 0 then "Dodatnia" else "Brak kwoty lub ujemna"
Co wiemy? Warunki if powinny nie tylko oddawać intencję biznesową, ale też tworzyć kolumny o stabilnych typach, dzięki czemu kolejne kroki transformacji pozostają przewidywalne.

Łączenie warunków: and, or, not i pułapki czytelności
Podstawowe operatory logiczne and, or, not
Proste porównanie rzadko wystarcza w regułach, które mają rozróżniać kilka cech rekordu. Do łączenia warunków język M używa trzech spójników:
and– oba warunki muszą być prawdziwe,or– wystarczy, że jeden warunek będzie prawdziwy,not– negacja warunku.
Przykład typowego warunku biznesowego: aktywny klient z dodatnią kwotą:
if [Status] = "Aktywny" and [Kwota] > 0
then "Aktywny z przychodem"
else "Inny"
Gdy warunki zaczynają się mieszać, przydają się nawiasy klarującego kolejność:
if ([Status] = "Aktywny" or [Status] = "Nowy")
and [Kwota] > 0
then "Do analizy"
else "Poza zakresem"
Bez nawiasów and i or wykonują się według ustalonych priorytetów, co nie zawsze pokrywa się z zamiarem osoby projektującej regułę.
Tworzenie czytelnych warunków złożonych
Źle skonstruowany warunek z and i or potrafi wprowadzić w błąd nawet autora. Zamiast jednego rozgałęzionego zdania logicznego, często rozsądniej jest rozbić logikę na kilka prostszych kroków.
Najprostszy zabieg to wprowadzenie kolumny pomocniczej, która nazywa złożony warunek:
// krok 1: zdefiniowanie logicznej flagi
= Table.AddColumn(
#"Poprzedni krok",
"CzyAktywnyZPrzychodem",
each [Status] = "Aktywny" and [Kwota] > 0,
type logical
)
// krok 2: użycie flagi w kolumnie opisowej
= Table.AddColumn(
#"Krok 1",
"Segment",
each if [CzyAktywnyZPrzychodem] then "Aktywny z przychodem" else "Inny"
)
Zyskuje się dwie rzeczy: możliwość szybkiego przefiltrowania po samej fladze oraz warunek if, który sprowadza się do prostego if [Flaga] then ….
Negacja z not – gdy „nie” jest bardziej opisowe
Operator not pojawia się rzadziej, ale może poprawić czytelność, jeśli logika skupia się na wykluczeniach.
Zamiast:
if [Status] <> "Aktywny" and [Status] <> "Nowy"
then "Wyłączony"
else "Do analizy"
można wyrazić regułę wprost:
if not ([Status] = "Aktywny" or [Status] = "Nowy")
then "Wyłączony"
else "Do analizy"
Takie przekształcenie ma sens tam, gdzie „lista pozytywna” (wartości dopuszczone) jest znana i krótka. Warunek staje się wtedy bardziej zbliżony do zdania biznesowego: „jeśli status nie jest ani Aktywny, ani Nowy, traktuj jako wyłączony”.
Częste pułapki: zbyt długie linie i „przypadkowe or”
Łączenie kilku porównań w jednym wierszu utrudnia kontrolę nad logiką. Dobrą praktyką jest dzielenie warunków na linie tak, jak mówiłby o nich analityk:
if [Kwota] > 0
and [Status] = "Aktywny"
and ([Kraj] = "Polska" or [Kraj] = "Czechy")
then "Rynek główny"
else "Inny"
Odrębny problem to nadmierne użycie or zamiast obsługi wartości słownikowych w innym miejscu modelu (np. w słowniku krajów). Gdy w warunku pojawia się kilka lub kilkanaście powtórzeń or [Kraj] = "…", sygnał jest prosty: ta logika powinna zostać przeniesiona do odrębnej tabeli mapującej, a if ograniczyć do sprawdzenia przynależności do jednego z segmentów.
Zagnieżdżone if – kiedy są potrzebne, a kiedy szkodzą
Naturalne zastosowania zagnieżdżonych if
Zagnieżdżenie pojawia się zawsze, gdy liczba rozłącznych przypadków jest większa niż dwa. Drabinka if … else if … else jest wtedy prostą enumeracją możliwych stanów.
Przykład trzystopniowej klasyfikacji ryzyka:
if [Punktacja] >= 80 then "Wysokie"
else if [Punktacja] >= 50 then "Średnie"
else "Niskie"
Taki zapis jest czytelny, pod warunkiem, że liczba poziomów pozostaje umiarkowana, a kolejne gałęzie różnią się jednym warunkiem lub jednym progiem.
Jak czytać i pisać zagnieżdżenia, żeby nie zgubić else
Z technicznego punktu widzenia każde else if to po prostu kolejne if umieszczone w gałęzi else. Dla osoby patrzącej na kod pierwszy raz kluczowe jest prawidłowe wcięcie i łamanie wierszy.
Czytelny wzorzec:
each
if [Kwota] < 0 then "Ujemna"
else if [Kwota] = 0 then "Zero"
else if [Kwota] < 1000 then "Mała dodatnia"
else "Duża dodatnia"
Wcięcia i wyrównanie else if pod sobą od razu pokazują, że mamy do czynienia z jednym łańcuchem warunków, a nie kilkoma niezależnymi if w jednym kroku.
Granica zdrowego rozsądku: kiedy drabinka jest za długa
Problem pojawia się wtedy, gdy drabinka zagnieżdżonych if zaczyna sięgać kilkunastu gałęzi. Taki kod trudniej:
- przejrzeć pod kątem pokrycia wszystkich przypadków,
Alternatywy dla długich łańcuchów if
Kiedy liczba gałęzi zaczyna się rozrastać, lepiej szukać innych konstrukcji niż dorzucanie kolejnych else if. Pojawiają się trzy główne kierunki: tabelki mapujące, funkcje pomocnicze i przełączanie logiki na poziomie całych kroków, a nie pojedynczego warunku.
Słowniki i tabele mapujące zamiast listy else if
Gdy klasyfikacja opiera się na konkretnych wartościach (np. kody, statusy, kategorie), łańcuch if często da się zastąpić zwykłym dołączeniem tabeli słownikowej.
Zamiast:
if [Status] = "A" then "Aktywny"
else if [Status] = "N" then "Nowy"
else if [Status] = "Z" then "Zawieszony"
else if [Status] = "W" then "Wykluczony"
else "Nieznany"
da się w wielu przypadkach przygotować małą tabelę z dwoma kolumnami: Status i OpisStatusu, a następnie użyć kroku Merge lub funkcji Table.Join. Logika klasyfikacji wychodzi z kodu i staje się danymi, które można edytować bez otwierania Edytora Zaawansowanego.
Korzyść jest podwójna. Po pierwsze, warunek if znika albo sprowadza się do obsługi braków dopasowania (np. null -> "Nieznany"). Po drugie, użytkownicy biznesowi mogą modyfikować słownik w Excelu lub w innym źródle, bez ingerencji w samą transformację.
Funkcja pomocnicza jako „pudełko” na złożoną logikę
Druga technika przydaje się tam, gdzie warunki są liczne i oparte na przedziałach, progach lub kombinacjach kilku pól. Zamiast przepisywać tę samą drabinkę w wielu krokach, można wyodrębnić ją do funkcji:
// funkcja klasyfikująca ryzyko
(tPunktacja as number, tKwota as number) as text =>
let
Wynik =
if tPunktacja >= 80 and tKwota > 0 then "Wysokie – aktywne"
else if tPunktacja >= 80 then "Wysokie – nieaktywne"
else if tPunktacja >= 50 then "Średnie"
else "Niskie"
in
Wynik
W tabeli taka funkcja jest potem używana jak każda inna:
= Table.AddColumn(
#"Poprzedni krok",
"PoziomRyzyka",
each fxKlasyfikujRyzyko([Punktacja], [Kwota]),
type text
)
Sam łańcuch if nie stał się prostszy, ale został odseparowany i nazwany. Czytelność rośnie, bo w logice kroków pojawia się jasne: „tu klasyfikujemy ryzyko”, a nie kilkanaście powiązanych porównań.
Warunek na poziomie kroków: gdy różne scenariusze wymagają różnych ścieżek
Czasem problem zagnieżdżonych if wynika z tego, że próbują obsłużyć dwa scenariusze pracy zapytania w jednym kroku. Przykład: ten sam raport ma działać dla pliku źródłowego z dwiema lub trzema kolumnami, zależnie od wersji.
Zamiast skomplikowanych warunków w każdym Table.AddColumn, prostsze może być wprowadzenie rozgałęzienia na poziomie całego zapytania:
let
Źródło = Excel.Workbook(File.Contents(ŚcieżkaPliku), true),
Tabela = Źródło{[Name = "Dane"]}[Content],
MaKolumneX = Table.HasColumns(Tabela, {"KolumnaX"}),
Wynik =
if MaKolumneX then
// ścieżka przetwarzania dla nowej struktury danych
let
ZNowaKolumna = Table.AddColumn(Tabela, "Nowa", each [KolumnaX] * 2)
in
ZNowaKolumna
else
// ścieżka dla starej struktury danych
let
BezNowejKolumny = Table.AddColumn(Tabela, "Nowa", each null)
in
BezNowejKolumny
in
Wynik
Warunek if nie miesza się wtedy z logiką poszczególnych kroków, tylko rozdziela dwie kompletne ścieżki transformacji. Łatwiej zidentyfikować, co dzieje się „w wersji A” i „w wersji B” danych.
Typowe błędy przy zagnieżdżonych if i jak je wychwycić
Gdy drabinka robi się długa, rośnie ryzyko technicznych potknięć. Najczęstsze z nich to:
- gałąź, która nigdy nie zostanie spełniona (warunek zawsze przykryty przez wcześniejszy),
- brak obsługi ważnego przypadku (np. wartości
nulllub ujemnej), - mieszanie typów zwracanych w poszczególnych gałęziach.
Prosty przykład „martwej” gałęzi:
if [Punktacja] >= 80 then "Wysokie"
else if [Punktacja] >= 90 then "Bardzo wysokie"
else "Inne"
Drugi warunek nigdy się nie wykona, bo wszystko co >= 90, zostało już przechwycone przez pierwsze >= 80. Tego typu niespójności najlepiej wychwycić, sprawdzając warunki od strony matematycznej, nie tylko „na oko”.
W praktyce pomagają dwie proste techniki:
- Test próbki danych, w której ręcznie tworzy się rekordy „na skraju” przedziałów (wartości graniczne, zera,
null, nietypowe statusy) i sprawdza wynik kolumny warunkowej. - Tymczasowe przekształcenie łańcucha if w tabelę z przedziałami – choćby na kartce lub w osobnym arkuszu – tak, aby każdy zakres był opisany i rozłączny.
Refaktoryzacja istniejących if – porządkowanie po fakcie
Warunki rosną wraz ze zmianami w raporcie. Po kilku miesiącach zapytanie, które zaczynało się od prostego if, ma kilkanaście dopisków „na szybko”. Pytanie kontrolne brzmi: czy logika jest jeszcze odzwierciedlana w kodzie w sposób zrozumiały dla kogoś z zewnątrz?
Porządkowanie istniejących wyrażeń if można ująć w kilku krokach:
- Nazwanie intencji. Dla każdej złożonej kolumny warunkowej spisać, co ma robić w jednym zdaniu biznesowym (np. „oznacza klientów aktywnych z dodatnią sprzedażą w kraju podstawowym”).
- Wydzielenie powtarzających się fragmentów. Jeśli ten sam warunek występuje w kilku miejscach (np. „aktywny klient z przychodem”), przenieść go do osobnej kolumny logicznej lub funkcji pomocniczej.
- Sprawdzenie zakresów i kolejności. Uporządkować łańcuch tak, aby szedł „od najbardziej szczegółowego do najbardziej ogólnego” lub „od najwyższego do najniższego progu”, bez przeskakiwania.
- Rozdzielenie logiki technicznej i biznesowej. Obsługa błędów,
nulli typów danych może trafić do wcześniejszych kroków, a właściwa klasyfikacja działa na już „oczyszczonych” polach.
Rezultat to często krótszy kod lub przynajmniej taki, którego uzasadnienie da się opowiedzieć jednym ciągiem, bez wchodzenia w szczegóły implementacyjne co kilka znaków.
Projektowanie czytelnych if w praktyce Power Query
Równowaga między kreatorem a Edytorem Zaawansowanym
If w Power Query pojawia się zarówno w graficznych kreatorach (np. Kolumna niestandardowa), jak i bezpośrednio w Edytorze Zaawansowanym. Oba podejścia prowadzą do tego samego kodu M, ale ich użycie wpływa na czytelność i utrzymanie reguł.
Kreator kolumn pomaga użytkownikom zaczynać od prostych przypadków, natomiast przy bardziej złożonych warunkach szybciej jest edytować kod bezpośrednio. Typowy scenariusz roboczy wygląda tak:
- Stworzenie pierwszej wersji warunku w kreatorze – jedno lub dwa porównania.
- Przejście do Edytora Zaawansowanego i ręczne dopisywanie kolejnych gałęzi
else iflub nazwanych kroków pomocniczych. - Dostosowywanie wcięć i łamań wierszy tak, aby logika była „do przeczytania”, a nie tylko do wykonania.
Co istotne, zmiany wprowadzone ręcznie w kodzie mogą spowodować, że kreator nie odzwierciedli już poprawnie całej logiki. W takim układzie Edytor Zaawansowany staje się miejscem prawdy o warunkach, a kreator – tylko punktem startu.
Nazywanie kroków i kolumn jako wsparcie dla if
Nieraz sama treść if jest poprawna, ale trudna do zrozumienia, bo odnosi się do kolumn o mało mówiących nazwach, takich jak Column1, FlagA czy Val2. Fragment kodu:
if [FlagA] and [Val2] > 0 then "OK" else "NOK"
może być dla nowych osób w zespole całkowicie nieczytelny. Sytuacja zmienia się, gdy nazwy zostaną doprecyzowane:
if [CzyAktywnyKontrakt] and [KwotaNetto] > 0
then "Aktywny z przychodem"
else "Pozostali"
Kroki w M można również nazywać opisowo:
#"Dodano flagę aktywny z przychodem" =
Table.AddColumn(
#"Przefiltrowane okresy",
"CzyAktywnyZPrzychodem",
each [Status] = "Aktywny" and [Kwota] > 0,
type logical
)
Dla osób analizujących zapytanie po czasie nazwa kroku jest pierwszą wskazówką, co dzieje się w środku. Sam warunek if dzięki temu nie musi przenosić całego kontekstu w jednym zdaniu.
Rozdzielanie obliczeń i warunków: mniejsze klocki, prostsze if
Częsty wzorzec utrudniający życie to mieszanie obliczeń i warunków w jednym wyrażeniu. Przykład z życia: raport sprzedaży, w którym w jednym kroku oblicza się marżę, kurs waluty i jednocześnie klasyfikuje transakcję.
Zamiast jednego długiego if:
if [Waluta] = "PLN" and ([Przychód] - [Koszt]) / [Przychód] > 0.2
then "Wysoka marża PLN"
else if [Waluta] <> "PLN" and ([Przychód] * [Kurs]) - ([Koszt] * [Kurs]) > 10000
then "Wysoka marża w walucie obcej"
else "Pozostałe"
czytelniej jest wydzielić obliczenia do osobnych kolumn, a warunek oprzeć na gotowych polach:
// kolumna: MarżaProcent
= Table.AddColumn(
#"Poprzedni krok",
"MarżaProcent",
each if [Przychód] <> 0
then ([Przychód] - [Koszt]) / [Przychód]
else null,
type number
)
// kolumna: MarżaPLN
= Table.AddColumn(
#"Krok z marżą procentową",
"MarżaPLN",
each if [Waluta] = "PLN"
then [Przychód] - [Koszt]
else ([Przychód] * [Kurs]) - ([Koszt] * [Kurs]),
type number
)
// kolumna klasyfikująca
= Table.AddColumn(
#"Krok z marżą PLN",
"SegmentMarży",
each
if [Waluta] = "PLN" and [MarżaProcent] > 0.2 then "Wysoka marża PLN"
else if [Waluta] <> "PLN" and [MarżaPLN] > 10000 then "Wysoka marża walutowa"
else "Pozostałe",
type text
)
Warunki if zyskują na przejrzystości, bo zamiast formuł w środku pojawiają się nazwy kolumn odsyłające do już policzonych, stabilnych wartości.
Warunki defensywne: if jako zabezpieczenie przed błędami
Wyrażenia if pełnią także funkcję „bezpieczników” przed błędami, które mogłyby przerwać działanie całego zapytania. W raportach z wielu źródeł częsty jest scenariusz, w którym w jednej z kolumn sporadycznie pojawia się tekst zamiast liczby albo data w innym formacie.
Zamiast liczyć na to, że dane będą idealne, wygodniej dodać warunek defensywny:
if Value.Is([Kwota], type number)
then [Kwota]
else null
albo bardziej opisowo:
if Value.Is([Kwota], type number)
then [Kwota]
else error "Nieprawidłowy typ w kolumnie Kwota"
W pierwszym przypadku raport „przełyka” błędne wiersze i zamienia je na null. W drugim – zatrzymuje się z jednoznacznym komunikatem. Wybrana strategia zależy od tego, czy ważniejsze jest ciągłe działanie raportu, czy twarde pilnowanie jakości danych.
Co zostaje po stronie analityka, a co po stronie kodu
If w języku M to miejsce, w którym decyzje biznesowe spotykają się z techniczną reprezentacją danych. Część pracy polega na trafnym zapisaniu reguł, ale równie ważne jest zdecydowanie, w której warstwie modelu dana logika powinna się znaleźć:
- proste, jednorazowe rozróżnienia – bezpośrednio w kolumnach
if, - słowniki i mapowania – raczej w dodatkowych tabelach łączonych przez
Merge, - złożone scenariusze – w funkcjach pomocniczych lub rozgałęzieniach na poziomie kroków.
Najczęściej zadawane pytania (FAQ)
Jak napisać prosty warunek if w Power Query (język M)?
Podstawowa składnia w M wygląda tak: if <warunek logiczny> then <wartość gdy prawda> else <wartość gdy fałsz>. Czyli zawsze są trzy części: if, then i else. Warunek musi zwracać true/false, a nie tekst czy liczbę.
Przykład z praktyki: klasyfikacja transakcji po kwocie. Kod może wyglądać tak: if [Kwota] >= 0 then "Przychód" else "Koszt". Co wiemy? Dodatnie i zerowe wartości są oznaczane jako „Przychód”, wartości ujemne jako „Koszt”. Jeśli definicja się zmieni, wystarczy poprawić jedno wyrażenie.
Dlaczego w języku M część else w if jest obowiązkowa?
Silnik M wymaga pełnej konstrukcji if … then … else …. Nie ma możliwości zapisania „gołego” if bez else, bo interpreter nie wie, co zwrócić, gdy warunek okaże się fałszywy. Próba użycia zapisu typu if [Kwota] > 0 then "Przychód" zakończy się błędem składni.
Jeśli w gałęzi else „nic ma się nie dziać”, w praktyce stosuje się najczęściej:
null, gdy brak wartości jest akceptowalny, np.if [Kwota] > 0 then "Przychód" else null,- oryginalną wartość kolumny, np.
if [Kwota] > 0 then [Kwota] else [Kwota], gdy testujemy tylko samą strukturę warunku.
Czego nie wiemy bez spojrzenia w dane? Jak brak wartości (null) wpłynie na dalsze kroki raportu.
Czym różnią się kolumny warunkowe od kolumn niestandardowych w Power Query?
Kolumna warunkowa powstaje z kreatora w interfejsie („Kolumna warunkowa”) i jest wygodna przy prostych regułach. Power Query generuje wtedy za kulisami wyrażenie if … then … else …. Kolumna niestandardowa daje pełną kontrolę nad kodem – użytkownik sam wpisuje logikę warunków w języku M.
W praktyce:
- proste, pojedyncze reguły (np. „Kwota >= 0 to 'Przychód’”) łatwiej kliknąć w kreatorze,
- złożone warunki z wieloma zależnościami (and/or, kilka poziomów progów, różne typy danych) są czytelniejsze, gdy zapisze się je ręcznie jako jedno, dobrze ułożone wyrażenie if w kolumnie niestandardowej.
Z czasem widać, że nadmierne „klikanie” prowadzi do wielu kroków i długich, trudnych do czytania warunków.
Jak pisać czytelne warunki if w Power Query przy złożonej logice?
Przy wielu regułach biznesowych kluczowa jest struktura. Zamiast generować kolejne warunki z kreatora, warto:
- grupować powiązane warunki przy pomocy nawiasów i operatorów
and/or, - używać jasnych nazw kroków i kolumn (np.
DodajTypTransakcjizamiastKrok3), - wydzielać większe bloki logiki do funkcji pomocniczych, jeśli ta sama reguła pojawia się w kilku miejscach.
Przykład z życia: klasyfikacja klienta jako „VIP” może zależeć od obrotu i długości współpracy. Taką regułę lepiej zapisać w jednym, dobrze opisanym if niż rozbijać na kilka nieoczywistych kroków filtrowania i kolumn pomocniczych.
Jak poprawnie łączyć warunki w if (and, or, not) w języku M?
Do budowania złożonych wyrażeń logicznych M używa operatorów and, or oraz not. Proste reguły można łączyć, np.: if [Kwota] > 0 and [Status] = "Aktywny" then "OK" else "Sprawdź". Kluczowe jest to, że całe wyrażenie przed then nadal musi zwracać true/false.
Aby uniknąć nieporozumień, przy bardziej skomplikowanych warunkach dobrze jest używać nawiasów, np. if ([Kwota] > 0 and [Status] = "Aktywny") or [Priorytet] = "Wysoki" then …. Co wiemy dzięki nawiasom? Które warunki są ze sobą logicznie powiązane, a które traktowane są alternatywnie.
Jak radzić sobie z porównaniem tekstów w if, gdy dane mają różną wielkość liter?
Porównywanie tekstów w M jest domyślnie czułe na wielkość liter. Wyrażenie [Status] = "aktywny" nie zadziała na wartość „Aktywny”. W efekcie część wierszy może zostać niepoprawnie sklasyfikowana lub odfiltrowana.
Praktyczne podejście to wcześniejsze ujednolicenie tekstu:
- użycie
Text.Upper([Status])i porównanie do stałej zapisanej wielkimi literami, - alternatywnie –
Text.Lower, jeśli taki format jest wygodniejszy.
Przykład: if Text.Upper([Kraj]) = "POLSKA" then "PL" else "Inne". Dzięki temu przypadki „Polska”, „polska” czy „POLSKA” są traktowane identycznie.
W jaki sposób używać if z parametrami w Power Query (np. dla środowisk Test/Prod)?
Parametry w Power Query można podpiąć bezpośrednio do wyrażeń if i w ten sposób sterować scenariuszem przetwarzania danych. Przykład: parametr Środowisko z wartościami „Test” lub „Prod” może decydować, z którego źródła pobierane są dane.
Kod może wyglądać tak: if Środowisko = "Test" then ŹródłoTest else ŹródłoProd. Co to daje? Jedno zapytanie, które zmienia zachowanie w zależności od ustawienia parametru, bez ręcznej podmiany połączeń. Taka logika jest czytelna także dla kogoś, kto przejmuje raport po kilku miesiącach.
Bibliografia
- Power Query M formula language specification. Microsoft – Oficjalna specyfikacja składni i semantyki języka M
- Power Query M function reference. Microsoft – Dokumentacja funkcji M, w tym operatorów logicznych i porównań
- Introducing Microsoft Power BI. Microsoft Press (2016) – Kontekst użycia Power Query i logiki transformacji danych
- M is for (Data) Monkey: A Guide to the M Language in Excel Power Query. Holy Macro! Books (2014) – Omówienie języka M, składni if oraz zastosowań biznesowych






