LASTDATE vs MAX

DAXDAX 101

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.

LASTDATE ve MAX Farkı Ne?

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] )
lastdate


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 üyeler görebilir. Hızlı üyelik için sosyal medya hesabınızla giriş yapabilirsiniz!

Bloga sosyal medya hesabınızla hızlı üye olmak için ilgili ikonu tıklayabilirsiniz.

Yorum yapın

PowerBI İstanbul

Microsoft Power BI, Microsoft Fabric, veriyle ilgili Azure servisleri, veri analitiği, iş zekası, veri modelleme ve veri görselleştirme üzerine Türkçe bilgi içeriğine katkı sağlamayı amaçlar.

Intellect BI blog sitesidir. Intellect BI & PowerBI İstanbul, Microsoft Data Analytics ve Power BI Partneri 'dir.

Blog Yazılarına Üye Olun

Blog yazıları, eğitim ve meetup duyuruları posta kutunuza gelsin!

9,4K Üye