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

Hiyerarşiler: ebeveyn-çocuk, düzensiz hiyerarşi, hiyerarşiye göre hesap

PATH, PATHITEM, PATHLENGTH, PATHCONTAINS; ebeveyne göre pay; ISINSCOPE ile düzey bilinçli ölçüler.

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ç.

Doğal hiyerarşi ve ebeveyn-çocuk hiyerarşisi

Kategori → Ürün ya da Yıl → Çeyrek → Ay gibi doğal hiyerarşiler farklı sütunlarda durur ve matrise satır satır eklenir. Organizasyon şeması ise tek tabloda ebeveyn-çocuk (parent-child) biçimindedir: Calisanlar[CalisanNo] ve Calisanlar[YoneticiNo]. Derinlik sabit değildir; buna düzensiz (ragged) hiyerarşi denir.

PATH ailesi

-- Hesaplanmış sütunlar (Calisanlar tablosunda):
Yol = PATH(Calisanlar[CalisanNo], Calisanlar[YoneticiNo])        -- "1|2|9"
Seviye = PATHLENGTH(Calisanlar[Yol])                             -- 3
Seviye1 = LOOKUPVALUE(Calisanlar[AdSoyad], Calisanlar[CalisanNo], PATHITEM(Calisanlar[Yol], 1, INTEGER))
Seviye2 = LOOKUPVALUE(Calisanlar[AdSoyad], Calisanlar[CalisanNo], PATHITEM(Calisanlar[Yol], 2, INTEGER))
Seviye3 = LOOKUPVALUE(Calisanlar[AdSoyad], Calisanlar[CalisanNo], PATHITEM(Calisanlar[Yol], 3, INTEGER))

Seviye1–3 sütunları matrisin satırlarına konunca organizasyon şeması açılıp kapanan bir hiyerarşi olur. Boş seviyeleri gizlemek için düzey bilinçli bir ölçü kullanılır:

Satış (Hiyerarşi) =
VAR Derinlik = MAX(Calisanlar[Seviye])
VAR GosterilenDuzey =
    ISINSCOPE(Calisanlar[Seviye1])
        + ISINSCOPE(Calisanlar[Seviye2])
        + ISINSCOPE(Calisanlar[Seviye3])
RETURN
    IF(GosterilenDuzey <= Derinlik, [Ekip Satışı])

Matris, bir çalışanın gerçek derinliğinden daha alt bir düzeyi gösteriyorsa (ör. temsilcinin altında boş bir “Seviye4”) ölçü boş döner ve o satır gizlenir. TRUE/FALSE değerleri toplanınca 1/0 olur.

Ekibin toplamı: PATHCONTAINS

Bir yöneticinin satırında, hiyerarşide altındaki herkesin toplamı:

Ekip Satışı =
VAR Kisi = SELECTEDVALUE(Calisanlar[CalisanNo])
RETURN CALCULATE([Net Satış], FILTER(ALL(Calisanlar), PATHCONTAINS(Calisanlar[Yol], Kisi)))

Hiyerarşide pay: ebeveyne göre

Matriste Kategori → Ürün varken, ürün satırında ürünün kategorisi içindeki payını, kategori satırında kategorinin genel paydaki yerini göstermek:

Ebeveyne Göre Pay % =
SWITCH(
    TRUE(),
    ISINSCOPE(Urunler[Urun]),
        DIVIDE([Net Satış], CALCULATE([Net Satış], ALLSELECTED(Urunler[Urun]))),
    ISINSCOPE(Urunler[Kategori]),
        DIVIDE([Net Satış], CALCULATE([Net Satış], ALLSELECTED(Urunler[Kategori]))),
    1
)

ISINSCOPE en alt düzeyden başlayarak kontrol edilir: ürün düzeyinde kategori de “kapsamda”dır.

Uzmanlaş

Bu modelin organizasyon ağacı

Calisanlar tablosunda 27 kişi ve üç düzey var: Genel Müdür Selim Aksoy (düzey 1), altında altı müdür (düzey 2), onların altında 20 uzman ve temsilci (düzey 3). Satış yapanlar Satış Müdürü Elif Doğan ve ekibindeki beş kişi. Satışın 183.134,35 ₺'si düzey 2'de (Elif Doğan'ın kendisi), 1.067.638,10 ₺'si düzey 3'te.

Bu yapı, gerçek şirketlerde sık görülen bir sorunu taşır: müdür hem yönetir hem satar. Matris açıldığında müdürün kendi satışı nereye düşer? Bu soru düzensiz hiyerarşinin (ragged hierarchy) özüdür.

Düzensiz hiyerarşi: boşluklar nereden gelir?

Matrise Seviye1 → Seviye2 → Seviye3 sütunları konduğunda Elif Doğan'ın satırı düzey 2'de biter; Seviye3 değeri boştur. Matris onun 183.134,35 ₺'lik kendi satışını Elif Doğan'ın altında "(Boş)" adlı bir satırda gösterir. Kullanıcı "Boş kim?" diye sorar. Üç çözüm:

ÇözümArtıEksi
Boş düzeyi ISINSCOPE'lu bir ölçüyle gizlemek (ana bölümdeki "Satış (Hiyerarşi)")Model değişmezMüdürün kendi satışı hiçbir alt satırda görünmez, yalnızca toplamında
Boş düzeyi kişinin kendi adıyla doldurmakHer tutar adı olan bir satırdaMüdür kendi altında bir kez daha görünür
Boş düzeyi "(kendi satışı)" gibi bir etiketle doldurmakAçık ve okunurEtiket kuralı belgelenmeli
-- Calisanlar tablosunda hesaplanmış sütun
Seviye3 (Dolu) =
VAR Kendi = Calisanlar[AdSoyad]
VAR Uc = LOOKUPVALUE(
    Calisanlar[AdSoyad], Calisanlar[CalisanNo],
    PATHITEM(Calisanlar[Yol], 3, INTEGER)
)
RETURN IF(PATHLENGTH(Calisanlar[Yol]) < 3, Kendi & " (kendi satışı)", Uc)

Hangi çözümü seçersen seç, matrisin toplamları değişmez; değişen, kullanıcının tutarı nerede bulduğudur. Organizasyon raporlarında en az soru getiren seçenek genellikle üçüncüsüdür.

PATH ailesi: derinlemesine

FonksiyonGamze Özkan için (Yol = "1|2|8")Not
PATHLENGTH(Yol)3Düzey
PATHITEM(Yol, 1, INTEGER)1Kök (Genel Müdür)
PATHITEMREVERSE(Yol, 2, INTEGER)2Sondan ikinci: doğrudan yönetici
PATHCONTAINS(Yol, 2)DOĞRUElif Doğan'ın ağacında mı?

PATHITEM'in üçüncü bağımsız değişkenini unutma: varsayılan dönüş türü metindir. Metin "2" ile tamsayı CalisanNo, LOOKUPVALUE'da eşleşmez. Microsoft Learn'deki kurallar, PATH sütunu yenilemede hata vermeden önce veri kalitesini kontrol etmeni gerektirir:

  • Kimlik ve ebeveyn sütunu aynı türde olmalı: ikisi de metin ya da ikisi de tamsayı.
  • Ebeveyn sütunu boşsa PATH yalnızca kişinin kendi kimliğini döndürür (kök).
  • Ebeveyn sütunundaki her değer kimlik sütununda bulunmalı.
  • Kimlikte dikey çizgi (|) varsa hata alırsın.
  • Aynı kimlik farklı ebeveynlerle iki kez geçiyorsa hata alırsın.
  • DirectQuery modunda hesaplanmış sütunda ve RLS kuralında desteklenmez.

Yenilemeden önce şu sorguyla "yöneticisi tabloda olmayan" kayıtları ara:

EVALUATE
EXCEPT(VALUES(Calisanlar[YoneticiNo]), VALUES(Calisanlar[CalisanNo]))

Bu modelde tek satır gelir ve değeri boştur: kök çalışanın boş YoneticiNo'su. Başka bir değer gelirse PATH o çalışanda hata verecek demektir.

Yönetici bazında toplama: üç farklı soru

İK direktörü "Elif Doğan'ın satışı ne kadar?" diye soruyor. Bu cümle üç farklı sayıya karşılık gelebilir:

SoruÖlçü fikriElif DoğanSelim Aksoy
Kişinin kendi satışı[Net Satış]183.134,35boş
Doğrudan bağlılarıCalisanlar[YoneticiNo] = Kisi1.067.638,10183.134,35
Tüm alt ağaç (kendisi dahil)PATHCONTAINS(Calisanlar[Yol], Kisi)1.250.772,451.250.772,45

Mekanizma: FILTER(ALL(Calisanlar), PATHCONTAINS(Calisanlar[Yol], Kisi)), satırdaki kişiye ait filtreyi kaldırır ve yerine ekibin satırlarını koyar. Bu filtre TemsilciNo ilişkisi üzerinden Satislar'a iner. Raporda hangi sayının gösterildiği başlıkta yazmalı; yoksa üç ayrı toplantıda üç ayrı rakam konuşulur.

Ekip içindeki pay da aynı mantıkla hesaplanır: payda, kişinin yöneticisinin alt ağacıdır. Gamze Özkan'ın payı Elif Doğan ağacının %21,2'si; Elif Doğan'ın kendi payı ise Genel Müdür ağacının %14,6'sı.

RLS ile birlikteSatır düzeyi güvenlik (RLS) kişiyi kendi alt ağacıyla sınırlıyorsa (ör. PATHCONTAINS(Calisanlar[Yol], ...USERPRINCIPALNAME()...)), ölçüdeki ALL(Calisanlar) RLS'nin gizlediği satırları geri getirmez. Müdür kendi ekibinin toplamını doğru görür; temsilci yalnızca kendini görür. "Şirket toplamına göre pay" ise RLS altında "görebildiğim toplama göre pay" olur. Bu farkı raporun kullanım notuna yaz.

ISINSCOPE ile düzeye göre farklı hesap

Satış direktörü Departman → Çalışan matrisi istiyor: çalışan satırında kişinin tüm alt ağacının satışı, departman satırında departmanın satışı görünsün.

Düzeye Göre Ekip Satışı =
SWITCH(
    TRUE(),
    ISINSCOPE(Calisanlar[AdSoyad]), [Ekip Satışı],
    ISINSCOPE(Departmanlar[Departman]), [Net Satış],
    [Net Satış]
)

Bunun bir bedeli var: alt toplam artık çocukların toplamı değildir. Satış departmanı satırı 1.250.772,45 ₺ gösterir; altındaki çalışan satırlarının toplamı ise 2.318.410,55 ₺'dir, çünkü Elif Doğan'ın satırı ekibinin satışını da içerir. Kullanıcı satırları toplarsa yanlış sonuca varır. Bu tür ölçülerde:

  • Ölçünün adı farkı söylesin ("Ekip Satışı (alt ağaç)").
  • Kenara bir not ekle: "Çalışan satırları toplanmaz."
  • ISINSCOPE kullan, HASONEVALUE değil: dilimleyicide tek departman seçiliyken HASONEVALUE toplam satırında da DOĞRU döner; ISINSCOPE yalnızca o düzey matriste gerçekten açıkken DOĞRU döner.

Kontrol listesi

  1. Kök kayıt dışında, yöneticisi tabloda olmayan çalışan var mı? (EXCEPT sorgusu)
  2. PATHITEM'de dönüş türü INTEGER mı?
  3. Müdürün kendi satışı matriste adı olan bir satırda görünüyor mu?
  4. "Kendi", "doğrudan bağlı" ve "alt ağaç" sayılarından hangisi gösteriliyor?
  5. RLS altında ALL'ın göremeyeceği satırlar düşünüldü mü?
  6. Düzeye göre değişen ölçüde alt toplamların çocukların toplamı olmadığı belirtildi mi?
Alıştırmalara geç (10)