Funkcja EARLIER w DAX – kilka słów o zagnieżdżaniu kontekstów

DAX posiada kilka koncepcji, które są nieco trudniejsze w zrozumieniu – jedną z nich bez wątpienia jest funkcja EARLIER i jej pochodna tj. EARLIEST, którą chciałbym omówić w ramach dzisiejszego artykułu – zapraszam do lektury.

Iteratory w modelach tabelarycznych to znany i lubiany (chyba) koncept. Wszyscy wiemy, że przykładem typowego iteratora są funkcję z sufiksem “X” jak np. SUMX, która wykonuje pewne działanie wiersz po wierszu (np. iloczyn ilość * cena), a następnie sumuje otrzymane rezultaty. To na co rzadziej zwraca się uwagę to fakt, że iteratory tworzą nowy kontekst wiersza w tabeli wskazanej jako pierwszy parametr funkcji iterującej.  W momencie gdy taki iterator umieścimy np. w kolumnie kalkulowanej to  powstaje coś na kształt zagnieżdżonych kontekstów wiersza – przyjrzyjmy się temu nieco bliżej. Za przykład posłuży scenariusz w którym istnieje potrzeba stworzenia rankingu produktów pod względem wysokości ich ceny tj. im droższy produkt tym wyżej jest w rankingu.W pierwszym kroku stworzona zostanie formuła w kolumnie kalkulowanej, która filtruje produkty w taki sposób aby pozostały tylko te, których cena jest mniejsza niż podana wartość– aby to osiągnąć użyjemy funkcji FILTER po to aby później policzyć wiersze spełniające warunek funkcją COUNTROWS.

W każdej z kolumn pojawi się ta sama liczba odzwierciedlająca liczbę produktów z ceną większą niż 10. Pożądanym efektem jest to aby zamiast 10 podstawić cenę dla bieżącego wiersza – dzięki temu policzona zostanie liczba produktów która ma większą cenę czyli nic innego jak miejsce bieżącego rekordu w rankingu cen bo jeżeli 5 produktów ma wyższą cenę niż bieżący produkt oznacza to, iż zajmuje on 6 miejsce w rankingu. FILTER sam w sobie możemy traktować jako iterator i wpisując w jego warunku zamiast 10 frazę

co daje nam dosyć kuriozalny efekt:

w powyższym przykładzie używając zapisu DimProduct[DealerPrice] nie odnosimy się do kontekstu bieżącego wiersza kolumny kalkulowanej tylko kontekstu funkcji FILTER, która jest aktualnie zagnieżdżona w kontekście bieżącego wiersza! Jak więc zatem dostać się do kontekstu kolumny kalkulowanej – pomijając kontekst narzucony przez FILTER? DAX udostępnia metodę na dostanie się do zewnętrznego kontekstu z poziomu zagnieżdżonego, a jest nią funkcja EARLIER. Dlatego też poniższy zapis porównuje bieżącą cenę jaką „widzi” FILTER z aktualnie przetwarzanym wierszem kolumny kalkulowanej.

Jak widać kilka produktów ma najwyższą cenę 2146 dolarów i dla nich w nowopowstałej kolumnie RANK nie wyświetla się żadna liczba – dzieje się tak dlatego, że żaden wiersz nie ma większej ceny dlatego FILTER zwraca BLANK. Dla większej przejrzystości do rezultatu można dodać 1

Taki wynik może już być zadowalający – co jednak gdy potrzeba stworzyć taki ranking, który produkty które mają np. drugie miejsce miały obliczony ranking 2 zamiast 6? Wystarczy spojrzeć na miarę i pomyśleć skąd wzięła się 6 – odpowiedź jest bardzo prosta ponieważ 5 produktów ma wyższą cenę. Obserwując rezultat można dojść do wniosku, że wszystkie 5 cen to tak naprawdę ta sama cena, to może w jakikolwiek sposób można by usunąć duplikaty z liczenia? Oczywiście, że tak! Do dyspozycji pozostają funkcję ALL, DISTINCT albo VALUES, które są funkcjami tablicowymi zwracającymi unikalną listę wartości z kolumny przekazanej jako parametr:

Teraz wygląda to już naprawdę dobrze prawda? Konstrukcja EARLIER nie jest zbyt intuicyjna ale po jej zrozumieniu może być przydatna. Pamiętajmy o niej w momencie gdy używamy zagnieżdżonych kontekstów wykonania. Jeżeli mimo wszystko nie przypadła Wam ona do gustu to w najnowszych wersjach silnika tabelarycznego (Power BI i SSAS) podobny efekt można uzyskać używając zmiennych:

Bieżąca wartość wiersza jest przechowywana w zmiennej i nie potrzeba odwoływać się do kontekstu zewnętrznego przy użyciu EARLIER – osobiście to podejście najbardziej mi się spodobało i staram się jego właśnie używać gdy zachodzi taka potrzeba.

Omawiana funkcja posiada również drugi opcjonalny parametr, który mówi o ile kontekstów należy się cofnąć, podobną funkcją jest EARLIEST, która cofa się do najbardziej zewnętrznego kontekstu jednakże w praktyce bardzo rzadko spotyka się zagnieżdżenie więcej niż dwóch kontekstów wiersza. Samo rozwiązanie problemu rankingu zapożyczyłem od Alberto Ferrariego, który obok Marco Russo jest niebywałym autorytetem w dziedzinie modeli tabelarycznych – tak więc jeśli ktoś chce dowiedzieć się czegoś więcej na te tematy zapraszam na ich stronę sqlbi.com – ponadto w najbliższym czasie na seequality pojawi się kilka dodatkowych opisów funkcjonalności DAX, które mam nadzieję okażą się dla was przydatne.

Adrian Chodkowski
Follow me
Latest posts by Adrian Chodkowski (see all)

Leave a Reply

Your email address will not be published. Required fields are marked *