DAX’ta doğru sonuçlara ulaşmak için göz önünde bulundurulması gereken birçok nokta var. Fonksiyonların çalışma detayları, birbirleriyle etkileşimleri, hangi durumda hangi alternatif yaklaşımın izlenmesi gerektiği konusu bazen biraz karmaşık gelebilir. Bugün, kullanırken dikkatli olunması gereken fonksiyonlardan birine, ALLEXCEPT() fonksiyonuna daha yakından bakıyoruz.
ALLEXCEPT() fonksiyonu iki temel kullanım alanı var. Tablo döndürebilir ya da daha popüler kullanımıyla CALCULATE() içerisinde filtreleme yapabilir. Belirtilen tablodan tüm fltreleri kaldırır, yalnızca haricen tutulması istenen filtreleri tutar. Bu tanım işlevini anlatma konusunda doğru sayılabilirse de içerdiği riskleri anlamak gerekli.
ALLEXCEPT() fonksiyonunda haricen tutulması için tanımladığınız filtrelerin hepsi, ölçüyü kullanıldığınız görselinize uygulanıyorsa riski pek görünür değil. Görselinizden, birinin bile etkisini kaldırırsanız öngörünüzün dışında sonuçlarla karşılaşabilirsiniz! Örnekle devam edelim. Marka ve sınıf adına göre ürünleri gruplamak istediğimizi düşünelim.
SENARYO 1: ALLEXCEPT() Fonksiyonunda Haricen Tutulan Filtrelerin Hepsi Görsele Etki Eder:
MarkaSınıf Satışları > 500M ALLEXCEPT() =
VAR _AllExceptIle =
CALCULATE (
[Satış Döviz Tutarı],
ALLEXCEPT(
'Product',
'Product'[BrandName],
'Product'[ClassName]
)
)
RETURN _AllExceptIle
Ölçüde BrandName ve ClassName filtrelerinin tutulmasını ve ikisi hariç diğer tüm filtrelerin kaldırılmasını istediğimizi ifade ediyoruz Örneğimiz kapsamında oluşturacağımız tablo için sırasıyla şu adımları gerçekleştirelim:
- Görsel ifadeyi sadeleştirmek için, aynı kırılımda 500 M’dan fazla satış tutarı olan siparişleri süzelim
- ALLEXCEPT() ile yazılan ölçünün davranışını gözlemlemek için alternatif bir ölçü oluşturalım
- İki ölçüyü birbirine bölelim ki sapma% farkları gözlemleyelim.
İlk madde ile başlayalım:
MarkaSınıf Satışları > 500M ALLEXCEPT() =
VAR _AllExceptIle =
CALCULATE (
[Satış Döviz Tutarı],
ALLEXCEPT(
'Product',
'Product'[BrandName],
'Product'[ClassName]
)
)
RETURN
IF(_AllExceptIle > 5 * POWER(10,8), _AllExceptIle)
Formül sonuçlarını kıyaslayabilmek için, iki sütunu gruplayarak satış tutarını hesaplayan farklı bir ölçü ekleyelim. Ardından iki formülü birbirine oranlayan bir formül daha ekleyelim:
MarkaSınıf Satışları > 500M SUMX() =
VAR _SatislarSUMX =
SUMX (
SUMMARIZE (
Sales,
'Product'[BrandName],
'Product'[ClassName]
),
IF (
[Satış Döviz Tutarı] > 5 * POWER ( 10, 8 ),
[Satış Döviz Tutarı]
)
)
RETURN _SatislarSUMX
MarkaSınıf Satışları SUMX / ALLEXCEPT =
DIVIDE(
[MarkaSınıf Satışları > 500M SUMX()],
[MarkaSınıf Satışları > 500M ALLEXCEPT()]
)
ALLEXCEPT() fonksiyonu ile yazdığımız formülün genel toplamı farklı, ölçüde tutmasını istediğimiz filtreleri değerlendirmeye almıyor gibi görünüyor. Ancak bu davranışın nedeni satır bağlamında hesaplama yapmıyor olması. Başka bir deyişle, SUMX()’in aksine, satır satır hesaplayarak oluşan sonuçları toplamıyor. Genel toplam ve tüm seviyelerdeki toplamlar için de filtre bağlamında hesaplama yapıyor.
Bu senaryo çerçevesinde, ALLEXCEPT() ile yazılan ölçü, liste elde etmekte ya da toplam gerekmeyen görsellerde kullanılabilir. Hatta bu şekilde kullanımı önemli performans kazancı sağlayabilir. Yakın bir örneği DAX Studio ile Performans Analizi yazımızda değerlendirmiştik.
SENARYO 2: ALLEXCEPT() Fonksiyonunda Haricen Tutulan Filtrelerden Biri Görsele Etki Etmez:
Senaryoyu görselleştirmek için, ölçüde tutulmasını istediğimiz ClassName’i görselden çıkaralım.
Toplamlarda gözlenen sonuçtan sonra, ALLEXCEPT() fonksiyonunun çalışmasına ilişkin dikkat edilmesi gereken ikinci nokta da daha görünür hale geldi. Görselden ClassName çıktığında, sanki ölçü formülünde ClassName hiç belirtilmemiş gibi davranıyor. Başka bir deyişle yalnızca BrandName filtresini haricen tutarak hesaplama yapıyor.
Daha güvenli kullanım için, bu davranışı kontrol altına almakta fayda var. Yalnızca BrandName ve ClassName sütunlarının her ikisi de görselde filtreleniyorsa ölçünün hesaplama yapmasını sağlayabiliriz. Gerekli koşulları ekleyerek devam edelim:
MarkaSınıf Satışları > 500M ALLEXCEPT() =
VAR _AllExceptIle =
CALCULATE (
[Satış Döviz Tutarı],
ALLEXCEPT(
'Product',
'Product'[BrandName],
'Product'[ClassName]
)
)
VAR _Kosullar =
ISINSCOPE('Product'[BrandName]) &&
ISINSCOPE('Product'[ClassName]) &&
_AllExceptIle > 5 * POWER(10,8)
RETURN
IF(_Kosullar, _AllExceptIle)
_Kosullar adıyla tanımladığımız değişken içerisinde 3 koşulun aynı anda var olup olmadığını değerlendirilmesini istedik.
- BrandName filtresi aktif olsun VE (&&)
- ClassName filtresi aktif olsun VE (&&)
- Gruplamada 500M üzeri satışlar filtrelensin.
Aynı zamanda toplam bilgilerini de sıfırlamış oluyoruz..
ISINSCOPE() ile tanımlanan sütunlardan biri, örneğin ClassName, filtre bağlamından çıkarılırsa FALSE döndüreceği için sonuç satırı boş görünecektir.
ALLEXCEPT() ile toplamlar konusunun sorun yaratabileceğini daha basit ifade etmek için şu ana dek tablo görseli kullandık. Her kademe toplamı gözleyebildiğimiz matrix görseline geçtiğimizde ISINSCOPE() fonksiyonunun ürettiği çözümü daha net gözlemleyebiliriz. Bir önceki örnekte kullandığımız görseli matrix görseline çevirelim:
ALLEXCEPT() fonksiyonu özetle performans açısından oldukça değerli bir fonksiyon ancak kullanılırken oldukça dikkatli olunması gerekiyor. CALCULATE() ile beraber kullanımında atlanan bir kullanım detayı, istenmeyen sonuçlar üretmesine kolaylıkla neden olabilir. Bu bakımdan görsel özelinde kullanımı daha güvenli. Handikaplarını azaltmak için ISINSCOPE() ile beraber kullanımını göz önünde bulundurmak esnekliğini bir miktar arttırabilir.
ALLEXCEPT() riskli olduğu kadar kullanım detayı da özel vakalar için kullanım alanı da geniş bir fonksiyon. Bu yazıda fonksiyonun temel sorunlarına ışık tutarak güvenli kullanımını örneklendirdik. Veri modeli genelinde kullanımı, bazı spesifik sorunların çözümünde kullanımı, performans stratejisi oluşturma, diğer alternatif yaklaşımlar gibi daha birçok yazıyı hak ediyorsa da bugünlük burada bırakalım. Bir sonraki yazıda görüşmek üzere.. DAX’la kalın..