Ana içeriğe geç
Kesit Power BI
İleri · İleri DAX

Tablo fonksiyonları, kümeler ve sanal ilişkiler

TREATAS, INTERSECT, EXCEPT, UNION, GENERATE, CROSSJOIN; soy bağı (lineage); köprü tablo ve çoka-çok ilişkiler.

Uygulamada aç, 11 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Tablo döndüren ifadeler bir “değer”dir

DAX'ta bir tablo ifadesi değişkende tutulabilir, filtre olarak verilebilir, satırları sayılabilir. İleri seviyenin anahtarı, tabloları kümeler gibi düşünmektir:

FonksiyonKüme işlemiÖrnek soru
INTERSECT(A, B)KesişimHem 2023 hem 2024'te alışveriş yapan müşteriler
EXCEPT(A, B)Fark2023'te alıp 2024'te almayan müşteriler (kayıp)
UNION(A, B)Birleşim (tekrarlar kalır)İki listenin birleşimi; DISTINCT ile tekilleştir
CROSSJOIN(A, B)Kartezyen çarpımTüm kanal × yıl kombinasyonları
GENERATE(A, ifade)A'nın her satırı için ifadenin döndürdüğü satırlarHer kategori için ilk 3 ürün
TREATAS(tablo, sütun…)Soy bağını değiştirirBağlantısız tablodaki değerleri modeldeki bir sütuna filtre olarak uygulamak

Soy bağı (lineage)

VALUES(Satislar[MusteriNo]) tek sütunlu bir tablodur ve sütunun modeldeki Satislar[MusteriNo] olduğunu “hatırlar”. Bu tablo CALCULATE'e verildiğinde Power BI hangi sütunu süzeceğini soy bağından bilir. {1, 2, 3} gibi elle yazılmış bir tablonun soy bağı yoktur; filtre olarak kullanılamaz. TREATAS soy bağını sonradan verir:

Kitap ve Spor = CALCULATE([Net Satış], TREATAS({"Kitap", "Spor"}, Kategoriler[Kategori]))

Sanal ilişki

Modelde ilişki olmayan iki tablo arasında, hesap anında ilişki kurmak. Örneğin bağlantısız KarsiUrunler tablosundaki seçimi Urunler'e uygulamak:

B Ürünleri Satışı =
CALCULATE(
    [Net Satış],
    TREATAS(VALUES(KarsiUrunler[KarsiUrunNo]), Urunler[UrunNo])
)

Alternatifleri: INTERSECT ile ya da FILTER(ALL(Urunler[UrunNo]), Urunler[UrunNo] IN VALUES(KarsiUrunler[KarsiUrunNo])). TREATAS genellikle en hızlı ve en okunur olanıdır. Sanal ilişki, hedefleri farklı tanecikte tutan bütçe tablolarında da sık kullanılır.

Çoka-çok ve köprü tablolar

Bir müşterinin birden çok segmente, bir ürünün birden çok kampanyaya ait olduğu durumlarda köprü (bridge) tablo kullanılır: Musteri ← KopruMusteriSegment → Segment. Filtrenin segmentten satışa ulaşması için köprü ile müşteri arasındaki ilişki çift yönlü olmalı ya da ölçüde CROSSFILTER(…, BOTH) kullanılmalıdır. Power BI'ın doğrudan “çoka-çok” kardinalitesi de vardır (iki tarafta da tekrar eden anahtar), ama sonuçları toplamlarda şaşırtıcı olabilir: bir satış iki segmentte sayılır, toplam ise bir kez sayar. Raporda bunun açıklanması gerekir.

PerformansBüyük olgu tablolarında FILTER(Satislar, …) ile sanal ilişki kurmak yavaştır. Sanal ilişkiyi boyut tablosunun anahtarı üzerinden (TREATAS(…, Urunler[UrunNo])) kur.
Derinleş

SUMMARIZE ile gruplama, ADDCOLUMNS ile hesaplama

SUMMARIZE’ın içinde hesaplanmış sütun ("Satış", [Net Satış]) tanımlamak çalışır ama önerilmez: SUMMARIZE bu sütunları beklenmedik bir filtre bağlamında hesaplayabilir ve sonuç, özellikle aynı tablodan birden çok sütunla gruplandığında yanıltıcı olur. Güvenli kalıp, gruplamayı SUMMARIZE’a, hesaplamayı ADDCOLUMNS’a bırakmaktır:

EVALUATE
ADDCOLUMNS(
    SUMMARIZE(Satislar, Urunler[Kategori]),
    "Satış", [Net Satış]
)

ADDCOLUMNS her satır için ölçüyü bağlam geçişiyle çağırır; yani her kategori satırında [Net Satış] o kategorinin filtresiyle hesaplanır. Yalnızca sorgu yazıyorsan SUMMARIZECOLUMNS daha da iyidir: gruplama ile hesaplamayı tek adımda yapar ve tüm ölçüleri BLANK olan satırları otomatik atar.

Uzmanlaş

SUMMARIZE: yalnızca var olan kombinasyonlar

Kanal müdürü soruyor: "Hangi ürün hangi kanalda hiç satılmadı?" Bu soru, iki tablo fonksiyonu arasındaki temel farkı gösterir:

İfadeSatırAnlamı
VALUES(Urunler[Urun])40Katalogdaki tüm ürünler
SUMMARIZE(Satislar, Urunler[Urun])38Satislar'da en az bir satırı olan ürünler
SUMMARIZE(Satislar, Urunler[Urun], Satislar[Kanal])113Gerçekleşmiş ürün-kanal çiftleri
CROSSJOIN(VALUES(Urunler[Urun]), VALUES(Satislar[Kanal]))120Olası tüm çiftler

SUMMARIZE olgu tablosunu tarar ve satırların gerçekten içerdiği kombinasyonları döndürür. Gruplama sütunlarını çoka-bir ilişkiler boyunca "bir" tarafından alabilir (Urunler[Urun]); ters yönde alamaz. CROSSJOIN ise tabloları birbiriyle çarpar ve veride hiç olmayan çiftleri de üretir. Aradaki 7 çift sorunun cevabıdır:

EVALUATE
FILTER(
    CROSSJOIN(VALUES(Urunler[Urun]), VALUES(Satislar[Kanal])),
    ISBLANK([Net Satış])
)

Sonuç: Robot Süpürge Web'de hiç satılmamış; Koşu Bandı ve Gurme Lokum Kutusu ise hiçbir kanalda. FILTER her çiftte [Net Satış]'ı çağırır; bağlam geçişi hem ürünü hem kanalı filtreye çevirir.

SUMMARIZE ham satırlara bakarSUMMARIZE iptal edilmiş satırları da sayar. "Satılmış" demek istiyorsan ya CALCULATETABLE ile Durum filtresi ekle ya da yukarıdaki gibi ölçü üzerinden kontrol et.

SUMMARIZECOLUMNS ve boş satırlar

SUMMARIZECOLUMNS, ifadelerinin hepsi BLANK olan satırları sonuçtan atar. Görsellerin "boş satırı göstermeme" davranışı buradan gelir. Bu kural küçük bir değişiklikle sonucun boyutunu değiştirir:

Sorgu (Urunler[Urun] × Tarih[Yil])SatırNeden?
"S", [Net Satış]111Satışı olmayan ürün-yıl çiftleri atılır
"S", [Net Satış] + 0120Hiçbir satır boş değil; 40 × 3 çiftin hepsi gelir
"S", [Net Satış], "K", [Kayıtlı Müşteri]120İkinci ölçü ürün filtresinden etkilenmez, hiç boş olmaz

Küçük modelde 9 fazladan satır zararsızdır. Müşteri × ürün × gün kırılımında ise "+0" ya da hiç boş olmayan bir ölçü, milyonlarca satırlık bir sonuç üretir; görsel yavaşlar ya da veri sınırına takılır. Sıfırı göstermen gerekiyorsa bunu yalnızca gereken görselde, sınırlı bir eksende yap.

Gerçek Power BI'da, bir ifadeyi boşluk kontrolünden çıkarmak için IGNORE vardır: o ifade boş olmasa da satır, diğer ifadeler boşsa atılır. Bu uygulamanın motoru IGNORE'u desteklemez; söz dizimi aşağıda:

EVALUATE
SUMMARIZECOLUMNS(
    Urunler[Urun], Tarih[Yil],
    "S", [Net Satış],
    "K", IGNORE([Kayıtlı Müşteri])
)

Ek bilgi: Eski kaynaklarda "SUMMARIZECOLUMNS'u ölçü içinde kullanma" uyarısını görürsün. Microsoft Learn'e göre Haziran 2024'ten bu yana SUMMARIZECOLUMNS her bağlam geçişinde çalışabiliyor ve ölçü içinde tam destekleniyor. Yine de sonuç sırası garanti edilmez; sıra gerekiyorsa sorguda ORDER BY kullan.

GENERATE ve CROSSJOIN: kombinasyon üretmek

Pazarlama her kanalın en iyi ayını görmek istiyor:

EVALUATE
ADDCOLUMNS(
    GENERATE(
        VALUES(Satislar[Kanal]),
        TOPN(1, CALCULATETABLE(VALUES(Tarih[YilAy])), [Net Satış])
    ),
    "Satış", [Net Satış]
)

Sonuç: Web 2024-12 (44.653,15 ₺), Mobil 2024-06 (41.208,05 ₺), Mağaza 2024-12 (17.423,45 ₺). Mekanizma: GENERATE ilk tablonun her satırı için ikinci ifadeyi o satırın satır bağlamında hesaplar. TOPN içindeki [Net Satış] bağlam geçişiyle hem dış satırı (Kanal) hem iç satırı (YilAy) filtreye çevirir. CALCULATETABLE, ay listesini kanala göre süzer; o kanalda satış olmayan aylar listeye girmez.

  • GENERATE, ikinci ifade boş tablo döndürürse o satırı atar (iç birleştirme gibi). Boş satırları tutmak için Power BI'da GENERATEALL vardır; bu uygulamada desteklenmez.
  • İki tablonun sütun adları çakışırsa hata alırsın; SELECTCOLUMNS ile yeniden adlandır.
  • CROSSJOIN maliyetini önceden hesapla: Musteriler × Urunler × Tarih = 150 × 40 × 1.096 = 6.576.000 satır. Bir ölçünün içinde bu boyutta tablo kurmak belleği ve süreyi patlatır.

Veri soyu nerede kaybolur?

Soy bağını ilk bölümde gördün. Üretimde soru şu: soy hangi adımda düşer? Soysuz bir tablo CALCULATE'e filtre olarak verilince Power BI'da ya hata alırsın ya da tablo hiçbir model sütununu süzmez. İki durumda da beklediğin sonuç gelmez.

AdımSoy
VALUES(Tarih[Yil]), FILTER(VALUES(...), ...), CALCULATETABLE(...)Korunur
ADDCOLUMNS(..., "Yeni", ifade) ile eklenen sütunYeni sütunun soyu yok
SELECTCOLUMNS(..., "Y", Tarih[Yil] - 1) gibi bir ifadeKaybolur
{ 2023, 2024 }, DATATABLE, GENERATESERIESHiç yok

Örnek: "Bir önceki yıllar" listesini elle üretip satışı süzmek istiyorsun. Listeyi SELECTCOLUMNS ile kurduğun anda soy düşer. TREATAS soyu yeniden verir:

-- Soy yok: filtre beklendiği gibi çalışmaz
Geçen Yıl (Hatalı) =
CALCULATE([Net Satış], SELECTCOLUMNS(VALUES(Tarih[Yil]), "Y", Tarih[Yil] - 1))
Geçen Yıl (TREATAS) =
CALCULATE(
    [Net Satış],
    TREATAS(SELECTCOLUMNS(VALUES(Tarih[Yil]), "Y", Tarih[Yil] - 1), Tarih[Yil])
)

2024 satırında 400.869,55 ₺ (2023'ün satışı) döner. Power BI'da SELECTCOLUMNS içindeki sade bir sütun başvurusu ("Y", Tarih[Yil]) soyu korur; ifade yazdığın anda korumaz. Bu uygulamanın motoru da aynı kuralı izler: sade başvuruda soy korunur, ifadede kopar. Emin olamadığında TREATAS ile soyu açıkça ver.

Tablo değişkenleri: bir kez hesaplanır, sabit kalır

Sabit Liste =
VAR T = VALUES(Urunler[Urun])
RETURN CALCULATE(COUNTROWS(T), Kategoriler[Kategori] = "Kitap")

Sonuç 7 değil 40'tır. VAR, tanımlandığı yerde ve o andaki filtre bağlamında bir kez hesaplanır. Sonradan gelen CALCULATE değişkenin içeriğini değiştiremez; yalnızca yeni ifadeleri etkiler. Kitap filtresinin listeye uygulanması için tablo ifadesi CALCULATE'in içinde yazılmalı: CALCULATE(COUNTROWS(VALUES(Urunler[Urun])), Kategoriler[Kategori] = "Kitap") 7 döndürür.

  • Bu davranış performans için iyidir: aynı tabloyu üç kez kullanacaksan bir kez hesaplanır.
  • Değişken tablonun eklenen sütunlarına [S] diye başvurursun; T[S] yazılamaz. Modelden gelen sütunlar özgün adlarıyla (Urunler[Urun]) kullanılır.
  • Değişken tablo soyunu korur; yani CALCULATE'e filtre olarak verilebilir.

Küme işlemlerinin kuralları

2023 ve 2024'te alışveriş yapan müşteri kümeleri (iptaller hariç) 77 ve 123 kişidir:

İşlemSonuçİş dili
INTERSECT(M2023, M2024)64İki yıl da alan
EXCEPT(M2023, M2024)132024'te gelmeyen
EXCEPT(M2024, M2023)592024'te 2023'te olmayan
UNION(M2023, M2024)200Tekrarlar kalır
DISTINCT(UNION(...))136Herhangi bir yılda alan
  • EXCEPT simetrik değildir; sıra yanlışsa "kayıp" yerine "yeni" sayarsın.
  • Sütunlar adla değil konumla eşleşir; sütun sayısı aynı olmalıdır. Sonucun sütun adları ve soyu ilk tablodan gelir.
  • Sonuç kümesi filtre olarak kullanılabilir: CALCULATE([Net Satış], EXCEPT(M2024, M2023), Tarih[Yil] = 2024) bu 59 kişinin 2024 satışını (315.901,35 ₺) verir.

Bu kümelerle tam bir müşteri köprüsü kurmayı İleri iş kalıpları dersinde, dönem tanımlarını Müşteri analitiği dersinde bulursun.

Kontrol listesi

  1. "Var olan" mı "olası" kombinasyon mu istiyorsun? SUMMARIZE ile CROSSJOIN'i buna göre seç.
  2. Sonuçta beklenmedik kadar çok satır var mı? Hiç boş olmayan bir ölçü aranıyor.
  3. Filtre olarak kullanacağın tablonun soyu hangi adımda düşüyor? Gerekirse TREATAS.
  4. Tablo değişkeni, sonradan değişmesini beklediğin bir filtreden önce mi tanımlandı?
  5. EXCEPT'in sırası iş sorusuyla aynı mı?
Alıştırmalara geç (11)