LASTDATE vs MAX

Herhangi bir transaction (fact) tablosundaki son değeri, son tarihi (veya ilkini) bulmak için LASTDATE, LASTNONBLANK ve MAX gibi fonksiyonları kullanabiliriz. Önceki yazılarda LASTDATE ve LASTNONBLANBK 'a değinmiştim. Tabii bunların ekürilerinin olduğunu da biliyoruz: FIRSTDATE, FIRSTNONBLANK ve MIN.

LASTDATE ile LASTNONBLANK arasındaki farklar nispeten bariz. Ama LASTDATE ile MAX arasındaki farklar o kadar net değil. Bu yazının amacı da bu farklara değinmek.

MAX bir aggregator, gördüğü context'teki en son nümerik değeri döndürür. (Tarih de nümerik bir sütundur). Döndürdüğü şey ise  nümerik (scalar) tek bir değerdir .

LASTDATE de gördüğü context'teki en son tarihi döndürür. LASTDATE, MAX'tan farklı olarak  sadece tarih (date) tipindeki sütunlarla çalışır . LASTDATE'in döndürdüğü şey ise  tek satır ve tek sütundan oluşan,  gördüğü context'teki en son tarihi içeren  bir tablodur . Yani scalar -sabit- bir değer değil tablo döndürür.

DAX, tek sütun tek satır içeren bir tabloyu  otomatik olarak gerektiğinde scalar bir değere dönüştürür . Ama tersi doğru değildir.

Bu yüzden bazı durumlarda her iki fonksiyon da aynı sonuçları döndürebilir, bazen ise tamamen başka hesaplamalara yol açabilir.

Örneklendirelim:

Son Tarih_LASTDATE := LASTDATE( 'Tarih'[Tarih] )
Son Tarih_MAX := MAX('Tarih'[Tarih] )


Dönen değerler -toplam satırları da dahil olmak üzere- aynı. Aynı sonucu döndürdükleri bir başka örnek yapalım. LASTDATE yazısındaki son 1 yıllık yürüyen satışlar formülünü bu sefer MAX 'la da yazalım.

Son 1 Yıllık Yürüyen Satışlar_LASTDATE := 
CALCULATE( [Satışlar] ;
      DATESINPERIOD( 'Tarih'[Tarih] ;
           LASTDATE( 'Tarih'[Tarih] ) ;
           -1 ;
           YEAR
      )
)
Son 1 Yıllık Yürüyen Satışlar_MAX := 
CALCULATE( [Satışlar] ;
      DATESINPERIOD( 'Tarih'[Tarih] ;
           MAX( 'Tarih'[Tarih] ) ;
           -1 ;
           YEAR
      )
)


Aynı rakamları döndürüyor her ikisi de. Buraya kadar her şey normal, çünkü birlikte kullandığımız diğer fonksiyonların bekledikleri syntax'a, parametre yapısına her ikisi de uyuyor.

Hazır bu metriği örneklendirmişken o yazıda eklemeyi unuttuğum bir başka metriği de yazıverelim: Yıllık yürüyen toplam satışlar lazım oluyor evet, yıllık yürüyen ortalama satışlar da en az bunun kadar lazım. Yapmamız gereken tek şey bu metriği ilgili context'teki ay sayısına bölerek hesaplamak.

Yürüyen Yıllık Ortalama := 
CALCULATE (
    DIVIDE ( [Satışlar] ; DISTINCTCOUNT ( 'Tarih'[Yıl  Ay] ) );
    DATESINPERIOD ( 'Tarih'[Tarih]; 
        MAX ( 'Tarih'[Tarih] ); 
        -1; 
        YEAR
    )
)

Her ayın sonundaki stok miktarını bulmak için gene önceki yazıda şöyle bir metrik yazmıştık:

Dönem Sonu Stok := CALCULATE( [Stok] ; LASTDATE( 'Tarih'[Tarih] ) )

Aynı metriği MAX ile yazmaya kalktığımızda yazdırmıyor bile!


CALCULATE'in filtre parametresine yazabileceğimiz şeyler bir tablo olabilir, bir tablo ifadesi olabilir veya tek sütunu refere ettiğimiz boolean tipinde bir "conditional" ifade olabilir.  Ama doğrudan scalar sabit bir değer olamaz!  Syntax'ı buna müsade etmiyor! Eğer MAX kullanarak dönem sonu stoğu hesaplamak istiyorsak yazdığımız formülün şeklini CALCULATE'in beklediği filtrelerin koşullarına uyacak şekilde değiştirmemiz lazım!

Dönem Sonu Stok__MAX := 
VAR SonTarih = MAX( 'Tarih'[Tarih] )
RETURN
CALCULATE( [Stok] ;
    'Tarih'[Tarih] = SonTarih
)


İki fonksiyon arasında birinin tek satır-tek sütunluk bir tablo (LASTDATE) diğerinin scalar bir değer (MAX) döndürüyor olmalarının haricinde bir fark daha var -ki bu en önemli fark-  LASTDATE eğer bir row context altında çalışıyorsa context transition gerçekleşiyor .

LASTDATE yazısında stoğu hesaplayan aşağıdaki gibi bir metrik yazmıştık:

Stok_MAX := 
CALCULATE( SUMX( 'Stok' ; ('Stok'[Giriş] - 'Stok'[Çıkış] ) * 'Stok'[Birim Maliyet] ) ;
         FILTER( ALL( 'Tarih' ) ;
            'Tarih'[Tarih] <= MAX( 'Tarih'[Tarih] ) 
         )
)

İlk tarihten itibaren giriş çıkış hareketlerinin kümülatif toplamını alan bir metrik. Aynı metriği LASTDATE ile yazıp matrise düşürüyorum.

Stok_LASTDATE := 
CALCULATE( SUMX( 'Stok' ; ('Stok'[Giriş] - 'Stok'[Çıkış] ) * 'Stok'[Birim Maliyet] ) ;
         FILTER( ALL( 'Tarih' ) ;
            'Tarih'[Tarih] <= LASTDATE( 'Tarih'[Tarih] ) 
         )
)


MAX'lı formül doğru stoğu bulurken LASTDATE'li versiyon her yerde aynı rakamı gösteriyor!

Çünkü bir row context altında çalışıyor, ki row context'i yaratan şey bu örnekte FILTER fonksiyonu ve context transition gerçekleşiyor! Buradaki

LASTDATE ( 'Tarih'[Tarih]

ifadesini  context transition gerçekleştiğinde  aşağıdaki gibi düşünmek mümkün

CALCULATETABLE (
    FILTER (
        ALL ( 'Tarih'[Tarih] ) ; 
        'Tarih'[Tarih] = MAX ( 'Tarih'[Tarih] )
    )
)

Internal açılımdaki MAX ( 'Tarih'[Tarih] ) orijinal formüldeki -en dıştaki- FILTER'ın iterate ettiği tarih tablosunun satırındaki Tarih!

 İçiçe iki tane row context oldu , en dıştaki orijinal FILTER + LASTDATE'in context transition yaratmasından kaynaklanan internal FILTER. En içteki row context, çalışırken  dıştaki filter context'i gizliyor! 
LastDate_Transition := 
CALCULATE (
    SUMX ( 'Stok'; ( 'Stok'[Giriş] - 'Stok'[Çıkış] ) * 'Stok'[Birim Maliyet] );
    FILTER (
        ALL ( 'Tarih' );
        'Tarih'[Tarih]
            <= CALCULATETABLE (
                FILTER ( ALL ( 'Tarih'[Tarih] ); 'Tarih'[Tarih] = MAX ( 'Tarih'[Tarih] ) )
            )
    )
)

** Şu ana kadarki en kompleks context transition örneği bu oldu sanırım. İç içe row context'lerin çalışmasını sakin sakin tekrar okumak isterseniz bu yazıya göz atmak isteyebilirsiniz: EARLIER.

Üzerinde düşünmek isterseniz anlamamıza yardımcı olacak şekilde formülü parçalayalım: internal açılımı tek başına bir metrik olarak yazalım.

Internal_LASTDATE := 
CALCULATETABLE ( 
    FILTER ( ALL ( 'Tarih'[Tarih] ) ; 'Tarih'[Tarih] = MAX ( 'Tarih'[Tarih] ) ) )

Satırdaki en son tarih neyse onu döndürüyor!

Aynı formülü bir hesaplanmış tablo olarak yazdığımızda – yani filter context olmadığında – tarih tablosundaki en son tarihi döndürüyor!


Yazıdaki modeli indirebilirsiniz.

Sadece kayıtlı üyeler görebilir. Giriş veya Üyelik için login.