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

DAX sorguları ve tablo fonksiyonları

EVALUATE, SUMMARIZECOLUMNS, ADDCOLUMNS, SELECTCOLUMNS, TOPN, DEFINE MEASURE ve ORDER BY.

Uygulamada aç, 10 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ç.

DAX sorgu görünümü

Power BI Desktop'taki DAX sorgu görünümü (ve DAX Studio gibi araçlar), bir tablo döndüren sorgular çalıştırır. Ölçüleri görsel kurmadan test etmenin, veriyi incelemenin ve hata ayıklamanın en hızlı yoludur. Bu uygulamadaki DAX Playground'nun “Sorgu” modu da aynıdır.

EVALUATE
SUMMARIZECOLUMNS(
    Kategoriler[Kategori],
    Tarih[Yil],
    "Net Satış", [Net Satış],
    "Hedef", [Hedef]
)
ORDER BY Kategoriler[Kategori], Tarih[Yil]

Tablo fonksiyonları

FonksiyonNe döndürür?
SUMMARIZECOLUMNS(sütunlar…, "Ad", ifade…)Grup başına satır + hesaplanmış sütunlar. Görsellerin arka planda ürettiği sorgu budur. Tüm ölçüleri boş olan satırları atar.
SUMMARIZE(tablo, sütunlar…)Tablodaki var olan grup kombinasyonları. Hesap eklemek için ADDCOLUMNS ile birlikte kullanılması önerilir.
ADDCOLUMNS(tablo, "Ad", ifade…)Tabloya hesaplanmış sütun ekler (her satırda bağlam geçişiyle).
SELECTCOLUMNS(tablo, "Ad", ifade…)Yalnızca seçilen ya da yeniden adlandırılan sütunlar.
TOPN(n, tablo, ifade)İlk n satır.
FILTER, VALUES, ALL, CALCULATETABLESüzülmüş ya da filtresiz tablolar.
{ }, ROW, GENERATESERIESElle tablo oluşturma.

Sorgu içinde ölçü tanımlamak

DEFINE
    MEASURE Satislar[Marj] = DIVIDE([Brüt Kâr], [Net Satış])
EVALUATE
TOPN(5, SUMMARIZECOLUMNS(Urunler[Urun], "Satış", [Net Satış], "Marj", [Marj]), [Satış])
ORDER BY [Satış] DESC

DEFINE MEASURE modeli değiştirmeden geçici bir ölçü tanımlar. Desktop'ta bu ölçüyü tek tıkla modele ekleyebilirsin.

Tek değer görmek

EVALUATE { [Net Satış] }

Birden çok değeri tek satırda görmek için ROW kullanılır:

EVALUATE ROW("Satış", [Net Satış], "Marj", [Kâr Marjı %])
Uzmanlaş

DAX sorgu görünümü bir test tezgâhıdır

Finans, "Net Satış" tanımından iadelerin de düşülmesini istiyor. Modeldeki ölçüyü hemen değiştirirsen ona bağlı onlarca ölçü ve rapor aynı anda değişir. Önce sorgu içinde dene:

DEFINE
    MEASURE Satislar[Net Satış (İadesiz)] =
        CALCULATE([Toplam Satış], NOT Satislar[Durum] IN {"İptal", "İade"})
EVALUATE
SUMMARIZECOLUMNS(
    Tarih[Yil],
    "Eski", [Net Satış],
    "Yeni", [Net Satış (İadesiz)],
    "Fark", [Net Satış] - [Net Satış (İadesiz)]
)
ORDER BY Tarih[Yil]

Fark 2022'de 11.621,15 ₺, 2023'te 26.035,75 ₺, 2024'te 43.178,45 ₺: bu, iade tutarlarıdır. Finansa "bu değişiklik 2024 net satışını 43 bin ₺ düşürür" diyebilirsin. Power BI Desktop'taki iş akışı (Microsoft Learn'e göre):

  1. Veri bölmesinde ölçüye sağ tık → Hızlı sorgular (Quick queries) → Değerlendir (Evaluate), Tanımla ve değerlendir (Define and evaluate) ya da Başvurularla tanımla ve değerlendir (Define with references and evaluate). Sonuncusu, ölçünün dayandığı ölçüleri de DEFINE bloğuna getirir.
  2. Tanımı düzenle, çalıştır, sonuçları eski tanımla karşılaştır.
  3. Ölçünün üstündeki CodeLens bağlantısı Modeli güncelle: Ölçünün üzerine yaz (Update model: Overwrite measure) ya da şeritteki Modeli değişikliklerle güncelle (Update model with changes) ile modele yaz.
  • Sorgudaki MEASURE, modelde aynı adlı bir ölçü varsa onu yalnızca o sorgu boyunca geçersiz kılar; model değişmez.
  • Ölçünün üstüne /// ile yazdığın açıklama, modele eklenince ölçünün açıklaması olur. Belgeleme işini burada yapmış olursun.
  • Sorgu sekmeleri Desktop dosyasıyla kaydedilir. Power BI proje (PBIP) biçiminde her sekme, anlamsal model klasöründeki DAXQueries klasörüne .dax dosyası olarak yazılır; yani test sorguların Git'e girer.
  • Canlı bağlantıda (live connect) model ölçüleri görüntülenemez ve "Modeli güncelle" seçenekleri yoktur.

Ölçü doğrulama sorguları

Her yeni ya da değiştirilmiş ölçü için birkaç sabit test yaz. Testin cevabı tek bir satır olsun; sonuç "GEÇTİ / KALDI" diye okunsun:

EVALUATE
VAR Beklenen = 1250772.45
RETURN
    ROW(
        "Net Satış", [Net Satış],
        "Durum", IF(ABS([Net Satış] - Beklenen) < 0.01, "GEÇTİ", "KALDI")
    )
TestSorgu fikriBu modelde
Toplam tutarlılığı[Net Satış] ile SUMX(VALUES(Kategoriler[Kategori]), [Net Satış]) eşit mi?İkisi de 1.250.772,45
Paylar toplamıSUMX(VALUES(Kategoriler[Kategori]), [Kategori Payı %]) = 1 mi?1
Zaman zekâsı31 Aralık 2024'teki [Satış YTD] = 2024 yılının satışı mı?İkisi de 747.065,70
HedefKategorilere dağıtılmış hedef toplamı = genel hedef mi?1.299.300
Kaynakla mutabakatKaynak sistemdeki (SQL, ERP) toplamla aynı mı?Kaynak sorgusuyla karşılaştır

Kayan nokta tuzağı: [Net Satış] - SUMX(...) sıfır değil, −0,000000000466 çıkar. Testleri doğrudan eşitlikle değil, küçük bir toleransla (ABS(fark) < 0.01) ya da ROUND ile yaz; yoksa doğru ölçü "KALDI" der.

SUMMARIZECOLUMNS + TREATAS: görseli sorguda kurmak

Bir görselin rakamı sorgulanıyor: "2024'te Web ve Mobil'de kategori satışları". Performans Analizi'nden görselin sorgusunu kopyaladığında hep aynı şekli görürsün: gruplama sütunları, dilimleyicileri temsil eden filtre tabloları ve ölçüler.

DEFINE
    MEASURE Satislar[Dijital Marj] = DIVIDE([Brüt Kâr], [Net Satış])
EVALUATE
SUMMARIZECOLUMNS(
    Kategoriler[Kategori],
    TREATAS({2024}, Tarih[Yil]),
    TREATAS({"Web", "Mobil"}, Satislar[Kanal]),
    "Satış", [Net Satış],
    "Marj", [Dijital Marj]
)
ORDER BY [Satış] DESC

Elektronik 168.910,60 ₺ ile başta, Hediye 8.700 ₺ ile sonda. Filtre tabloları dilimleyici gibi davranır; değerleri, gruplama satırları oluşturulmadan önce uygulanır. Üç kural:

  • SUMMARIZECOLUMNS sıra garantisi vermez; testlerde her zaman ORDER BY yaz.
  • Modeldeki "Sütuna göre sırala" (Sort by column) ayarı sorgu sonucuna uygulanmaz. Ay adlarını doğru sıralamak için AyNo'yu da sorguya alıp ona göre sırala.
  • Sonuç ızgarasındaki sıralama ve filtre yalnızca dönen satırlara uygulanır. Sorgu başına sınır 1.000.000 değerdir (20 sütunda en fazla 50.000 satır); büyük sonuçları doğrularken filtreyi sorgunun içine yaz.

ORDER BY, START AT ve DEFINE VAR

START AT, ORDER BY'ın içinde yer alır ve sonucun hangi değerden başlayacağını belirler. Değerler sabit olmalı; ORDER BY sütun sayısından fazla değer verilemez. Büyük bir listeyi sayfa sayfa dışa aktarırken işe yarar. Bu uygulamanın motoru START AT'i desteklemez:

EVALUATE
SUMMARIZECOLUMNS(Urunler[Urun], "Satış", [Net Satış])
ORDER BY Urunler[Urun] ASC
START AT "M"

İkinci bir tuzak: ORDER BY, TOPN'in hangi satırları seçeceğini belirlemez; yalnızca seçilenleri sıralar. "İlk 10" sorusunun sırası TOPN'in kendi sıralama bağımsız değişkenindedir.

DEFINE bloğunda VAR ile sorgu genelinde geçerli bir eşik tanımlayabilirsin. Belgeler DEFINE TABLE ve DEFINE COLUMN için "iç kullanım içindir, önerilmez" diyor; sorgu içi tablolar için VAR kullan:

DEFINE
    VAR Esik = 0.3
EVALUATE
FILTER(SUMMARIZECOLUMNS(Urunler[Urun], "Marj", [Kâr Marjı %]), [Marj] < Esik)

Marjı %30'un altında kalan 9 ürün gelir. Eşiği değiştirip yeniden çalıştırmak tek bir sayıyı düzenlemek kadar kolaydır.

Sorgu ile veri kalitesi kontrolü

Yeni bir veri kaynağı bağlandığında, rapor yazmadan önce tek bir "sağlık" sorgusu çalıştır. Bu modelde sonuçlar şöyle:

Kontrolİfade fikriSonuçYorum
Anahtar benzersiz mi?COUNTROWS(Satislar) - DISTINCTCOUNT(Satislar[SatirNo])0Bağlam geçişi güvenli
Yetim ürün satırıFILTER(Satislar, ISBLANK(RELATED(Urunler[Urun])))0Her satışın ürünü var
Negatif tutarSatislar[Tutar] < 00İadeler Durum ile işaretli
Teslim, siparişten önceTeslimTarihi < Tarih0Tarih mantığı tutarlı
Boş kargo günüISBLANK(Satislar[KargoGun])131121 iptal + 10 kargoda; beklenen
Tarih tablosu kesintisiz mi?COUNTROWS(Tarih) ile gün farkı + 11.096 = 1.096Eksik gün yok
Hiç almamış müşteriISEMPTY(RELATEDTABLE(Satislar))14Ortalama ölçülerinde dikkat
Şehri boş müşteriCOUNTBLANK(Musteriler[Sehir])7Harita ve bölge raporunda "(Boş)"
Hiç satılmamış ürünISEMPTY(CALCULATETABLE(Satislar))2Koşu Bandı, Gurme Lokum Kutusu
EVALUATE
ROW(
    "Satır", COUNTROWS(Satislar),
    "Yetim ürün", COUNTROWS(FILTER(Satislar, ISBLANK(RELATED(Urunler[Urun])))) + 0,
    "Boş kargo günü", COUNTROWS(FILTER(Satislar, ISBLANK(Satislar[KargoGun]))) + 0,
    "Tarih satırı", COUNTROWS(Tarih),
    "Gün sayısı", DATEDIFF(MIN(Tarih[Tarih]), MAX(Tarih[Tarih]), DAY) + 1,
    "Almayan müşteri", COUNTROWS(FILTER(Musteriler, ISEMPTY(RELATEDTABLE(Satislar)))) + 0
)

Boş bir FILTER üzerinde COUNTROWS 0 değil BLANK döndürür. Rapor ya da test çıktısında "0" görmek istiyorsan + 0 ekle.

Ekip çalışmasıSağlık sorgusunu ve ölçü testlerini PBIP projesinde DAXQueries klasöründe tut. Bir ölçüyü değiştiren kişi testleri çalıştırır ve sonucu çekme isteğine (pull request) ekler. Böylece "bu rakam neden değişti?" sorusunun cevabı kayıt altında olur.
Alıştırmalara geç (10)