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

DAX kullanıcı tanımlı fonksiyonları (UDF): tekrar eden mantığı tek yerde toplamak

Neden UDF (kopyala-yapıştır ölçü ve hesaplama gruplarıyla karşılaştırma), DAX sorgu görünümünde DEFINE FUNCTION ile tanımlayıp EVALUATE ile denemek, modele kaydetmek ve TMDL, imza tasarımı, parametre türleri, val ve expr geçiş modlarının bağlama etkisi, sınırlar.

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

Büyüyen bir modelde aynı mantık onlarca ölçüde tekrar eder: “geçen yıla göre değişim”, “payda sıfırsa boş döndür”, “şu kanalın payı”. Bir gün tanım değişir (ör. iadeler de düşülecek) ve sen otuz ölçüyü tek tek düzeltirsin; birini unutursun. DAX kullanıcı tanımlı fonksiyonları (user-defined functions, UDF) bu mantığı parametreli bir fonksiyon olarak bir kez yazmanı sağlar.

DurumUDF'ler 2025'te önizleme olarak geldi. Microsoft Learn'e göre Haziran 2026 sürümünden itibaren Power BI Desktop ve Service’te genel kullanımdadır ve veritabanı uyumluluk düzeyi 1702 ya da üstünü ister. Bu uygulamanın Playground motoru FUNCTION sözcüğünü desteklemez: UDF kodlarını okuyup anla, alıştırmalarda fonksiyon çağrısının açılmış (inline) hâlini yaz.

UDF mi, hesaplama grubu mu, düz ölçü mü?

Kopyala-yapıştır ölçüHesaplama grubuUDF
Nasıl uygulanır?Her ölçüde mantık yeniden yazılırGörseldeki ölçüye SELECTEDMEASURE() ile otomatik uygulanırÖlçünün içinde adıyla çağrılır
ParametreYokYok (yalnızca seçili ölçü)0–256 parametre, varsayılan değer
Kim seçer?Model yazarıRapor kullanıcısı (dilimleyiciyle)Model yazarı
Nerede çalışır?ÖlçüÖlçüler (örtük ölçüler hariç)Ölçü, hesaplanmış sütun, görsel hesaplama, başka UDF

İkisi rakip değil. Hesaplama grubu “kullanıcı Cari / GY / YTD arasında seçsin” sorusunu çözer (Hesaplama grupları, alan parametreleri, görsel hesaplamalar dersi). UDF ise “bu formülü otuz yerde aynı yazalım” sorusunu çözer. Bir hesaplama öğesi de içinde bir UDF çağırabilir.

İlk fonksiyon: tanımla ve EVALUATE ile dene

UDF'yi önce DAX sorgu görünümünde yazıp denemek en güvenli yoldur. DEFINE bloğunda FUNCTION anahtar sözcüğü, adı, parametre listesi ve => işaretinden sonra gövde gelir:

DEFINE
    /// Payı paydaya güvenli böler; payda 0 ya da boşsa BLANK döner.
    FUNCTION Pbi.Pay = ( pay : NUMERIC, payda : NUMERIC ) =>
        DIVIDE ( pay, payda )

EVALUATE
{ Pbi.Pay ( 10, 4 ), Pbi.Pay ( 10, 0 ) }
// 2,5 ve boş

/// ile başlayan satır fonksiyonun açıklamasıdır; IntelliSense bunu gösterir. Düz // ve /* */ yorumlar açıklama olarak görünmez. Sorgu düzgün çalışınca:

İmza tasarlamak: ad, parametre, tür

Fonksiyonun imzası (adı ve parametreleri) bir sözleşmedir; sonradan değiştirmek onu çağıran her ölçüyü etkiler. Learn'deki kurallar:

Tür ipucuAnlamıVarsayılan mod
AnyValSkaler ya da tablo değer (tür yazılmazsa bu)val
Scalar + alt türTek değer; alt tür Int64, Decimal, Double, String, DateTime, Boolean, Numeric, Variantval
TableTablo değerval
AnyRef, ColumnRef, TableRef, MeasureRef, CalendarRefSütun, tablo, ölçü ya da takvim başvurusuexpr (val yazılamaz)

Değer türleri örtük tür dönüşümü yapar: x : INT64 parametresine 3,4 verirsen 3 olur. Başvuru türleri dönüşüm yapmaz. Gövdede ISNUMERIC, ISSTRING, ISINT64 gibi denetim fonksiyonlarıyla gelen değeri kontrol edebilirsin.

val ve expr: argüman ne zaman hesaplanır?

Parametrenin geçiş modu UDF'lerin en önemli ve en kolay karıştırılan noktasıdır:

DEFINE
    FUNCTION Pbi.Yoy = ( olcu : SCALAR EXPR ) =>
        VAR Simdi = olcu
        VAR Once = CALCULATE ( olcu, SAMEPERIODLASTYEAR ( Tarih[Tarih] ) )
        RETURN DIVIDE ( Simdi - Once, Once )

    FUNCTION Pbi.YoyHatali = ( olcu : SCALAR VAL ) =>
        VAR Simdi = olcu
        VAR Once = CALCULATE ( olcu, SAMEPERIODLASTYEAR ( Tarih[Tarih] ) )
        RETURN DIVIDE ( Simdi - Once, Once )

EVALUATE
SUMMARIZECOLUMNS ( Tarih[Yil],
    "expr", Pbi.Yoy ( [Net Satış] ),
    "val", Pbi.YoyHatali ( [Net Satış] ) )

val sürümünde olcu artık bir sayıdır; CALCULATE bir sayının filtresini değiştiremez, “geçen yıl” da bu yılla aynı çıkar. Aynı davranışı motorda VAR ile görebilirsin; VAR da val gibi bir kez hesaplanır:

EVALUATE
SUMMARIZECOLUMNS(Tarih[Yil],
    "expr gibi", DIVIDE([Net Satış] - CALCULATE([Net Satış], SAMEPERIODLASTYEAR(Tarih[Tarih])),
                        CALCULATE([Net Satış], SAMEPERIODLASTYEAR(Tarih[Tarih]))),
    "val gibi", VAR S = [Net Satış]
                RETURN DIVIDE(S - CALCULATE(S, SAMEPERIODLASTYEAR(Tarih[Tarih])),
                              CALCULATE(S, SAMEPERIODLASTYEAR(Tarih[Tarih]))))

Sonuç: expr gibi 2023'te %289,8, 2024'te %86,4; val gibi her yıl 0. Kural basit: Fonksiyonun içinde argümanın bağlamını değiştireceksen (CALCULATE, yineleyici, zaman zekâsı) parametre expr olmalı. Yalnızca gelen sayıyla aritmetik yapacaksan (Pbi.Pay gibi) val yeterli ve daha ucuzdur; argüman bir kez hesaplanır.

Yineleyicide fark daha da büyür. AVERAGEX(VALUES(Tarih[YilAy]), olcu) gövdeli bir fonksiyonda expr parametre her ay için ayrı hesaplanır: filtresiz durumda satış olan 31 ayın ortalaması 40.347 TL'dir. Aynı parametre val olsaydı tek bir toplam (1.250.772) her aya tekrar yazılır ve “ortalama” toplamın kendisine eşit çıkardı.

Test etmek

  1. Bilinen değerle karşılaştır: EVALUATE { Pbi.Pay ( 10, 4 ) } gibi elle hesaplanabilen girdilerle başla.
  2. Hazır ölçüyle aynı mı? Fonksiyonla yazdığın ölçüyü eski ölçünün yanına bir tabloya koy: SUMMARIZECOLUMNS ( Tarih[Yil], "Eski", [YoY %], "Yeni", Pbi.Yoy ( [Net Satış] ) ). Her satır aynı olmalı.
  3. Kenar durumları: payda 0, BLANK, negatif değer, geçen yılı olmayan ilk yıl (2022).
  4. Modeldeki fonksiyonları listele: EVALUATE INFO.USERDEFINEDFUNCTIONS () modeldeki UDF'leri ve ifadelerini döndürür; belgelendirme ve gözden geçirme için kullanışlıdır.

Sınırlar (Learn'e göre)

Kütüphane gibi düşünFonksiyonları bir ad alanı altında topla (Finans., Zaman.), her birine /// açıklaması ve @param satırları yaz, bir test sorgusunu PBIP deposunda sakla. Fonksiyonu değiştirince test sorgusunu yeniden çalıştır.
Alıştırmalara geç (8)