Veri Modeline Giriş – Tablo İlişkileri

Veri modeli, tablolar arasında tanımlanmış "relationship" 'leri ve bu ilişkileri kullanarak hesapladığımız metrikleri içerir.

Tablolar arasında kurulan ilişkiler, modelin içerdiği tüm tablolar arasında "dolaşmamızı" sağlar.

Power BI'da "relationship" her zaman iki tablo arasında ve  tek sütun üzerinden  kurulur. İki tablo arasında ortak bir sütun üzerinden bir ilişki kurulduğunda, ilişkinin her zaman "tek tarafı" (one side table) ve "çoklu tarafı" (many side table) vardır.

Türkçe'de malesef yerleşmiş tam bir karşılıkları olmadığı için "one side" ve "many side" tanımlarını kullanacağım.

İlişkinin "one" tarafındaki ortak sütun  sadece ve sadece tekil değerleri içerebilir , yani sadece unik değerleri içeren bir sütun olabilir. İlişkinin one side tarafındaki tablonun her bir satırı için, many side tarafındaki tabloda bir veya daha fazla kayıt vardır. Ya da hiç kayıt olmayabilir.

PBI'da varsayılan (default) ilişki tipi "one-to-many"'dir ve tek yönlüdür (unidirectional). PBI, daha doğrusu  "tabular engine", one tarafındaki tablo "filtrelendiğinde", otomatik olarak many tarafındaki tabloyu da filtreler. 

Örnek modelde fatura satırlarının olduğu "Satışlar" tablosu, tekil tarihleri içeren "Tarih" tablosuyla ilişkilendirilmiştir. İlişki kurulan sütunların ismi her iki tabloda da aynı olmak zorunda değildir, fakat sütunların veri tipi aynı olmalıdır. Ekteki ilişkiyi oluşturmak için "Satışlar" tablosundaki "Fatura Tarihi" alanını sürükle-bırak yöntemiyle "Tarih" tablosundaki "Tarih" sütununa bıraktım. Bunu yaptığımda PBI one tarafındaki "Tarih" tablosundan many tarafındaki "Satışlar" tablosuna bir OK çizdi ve yönünü gösterdi.

Veri modelindeki tablolar arasındaki ilişkiyi gösteren okların yönü,  filtrenin akış yönüdür . Filtreler -siz aksini belirtmediğiniz sürece- her zaman "one" tarafındaki tablodan "many" tarafındaki tabloya doğrudur.

Satışların tutarını bulmak için basit bir komut yazalım;

Satışlar := SUM ('Satışlar'[Tutar] )

"Satışlar" metriğini matris görseliyle 3 farklı şekilde rapor ekranına getirelim;

İlkinde sadece "Satışlar" var. Tarih tablosundan herhangi bir filtreleme olmadığı için PBI, "Satışlar" tablosundaki tüm satırların "Tutar" değerlerini toplayıp getirdi.

İkincisinde ise satıra "Tarih" tablosundan "Yıl" sütunu eklendi. Yani Tarih tablosu yıl bazında  filtrelendi.   Yukarıdaki tanıma geri dönelim; PBI, one tarafındaki tablo filtrelendiğinde, otomatik olarak many tarafındaki tabloyu da filtreler. Dolayısıyla "Satışlar" metriğini her bir yıl için filtreleyerek getirdi.

Üçüncüsünde satıra hem yıl hem de ay getirildi: PBI, herhangi başka birşey yapmaya gerek kalmadan, Tarih tablosundan gelen her filtreyi otomatik olarak "Satışlar" tablosuna uyguladı ve matristeki  her bir hücre için  yaptığı tüm hesaplamaları ilgili filtrelere göre hesapladı.

Power BI, hesaplama yaparken, her bir hücreyi ayrı ayrı ilgili filtreler altında hesaplar. Basit bir cümle, ama çok önemli bir cümle.

İkinci matristeki 2001 yılına ait satışların gösterildiği hücre için PBI hesaplama yaparken tabular engine şöyle çalışır: Tarih tablosundan 2001 yılına ait tüm Tarih değerlerini bul, aradaki ilişkiyi kullanarak ok yönünde Satışlar tablosuna atla, ilgili tarihlerin olduğu (2001 yılına ait tüm tarihler) bulabildiğin tüm satırları "Satışlar" tablosunda bul, bulduğun satırlardaki "Tutar" değerlerini topla.

Üçüncü matristeki 2001, 8. aya ait satış değerini gösteren hücreyi hesaplarken de benzer cümleleri kurar: Tarih tablosundan 2001 8. aya ait tüm tarih değerlerini bul, ilişki üzerinden Satışlar tablosundan bu tarihleri içeren tüm fatura satırlarını bul, bulduğun satırlardaki "Tutar" değerlerini topla.

Modele "Ürünler" tablomuzu da ekleyelim, Satışlar tablosuyla "Ürün ID" üzerinden ilişkisini kuralım :

Ürünler tablosu, tekil ürün kodlarını içeren, kategori, sınıf vs. gibi diğer "master" ürün tanımlarını içeren bir tablo.

Kategori-Yıl ve Satışlar metriğinin olduğu bir matris ekleyelim:

Sadece tablolar arası ilişkileri tanımlayarak ve basit bir formül yazarak, satışları ürün bazında, ürün kategorisi, yıl, ay vs bazında görebiliyoruz. "One side" tarafındaki tabloların tüm sütunlarını satışları "kırmak" için kullanabiliriz. PBI, her bir filtreyi, filtre kombinasyonunu otomatik olarak "Satışlar" tablosuna uygular.

Modele iki formül daha ekleyelim:

Satış Yapılan Ürün Sayısı := DISTINCTCOUNT ('Satışlar'[Ürün ID] )
Ürün Sayısı := DISTINCTCOUNT ('Ürünler'[Ürün ID] )

Metriklerden ilki "Satışlar" tablosundaki tekil Ürün ID'lerini sayıyor, diğeri ise "Ürünler" tablosundaki tekil Ürün ID'lerini sayıyor.

Eklediğimiz metrikleri, satışlar ve yılla birlikte bir matriste gösterelim:

Tabular engine, aradaki ilişkiyi kullanarak OK yönünde "Satışlar" tablosuna atlayıp her bir yıl için "Satışlar" ı ve "Satış Yapılan Ürün Sayısı"'nı bulabiliyor. Fakat "Ürün Sayısı"'nı hesaplamak istediğinde, ok yönünde "Ürünler" tablosuna  geçemediği için  filtreyi bu tabloya otomatik uygulayamıyor. Filtreyi uygulayamadığı için de, "Ürünler" tablosunda bulduğu  tüm  tekil Ürün ID'lerinin sayısını döndürüyor.

Tabular engine'nin Ürün Sayısı metriğini her bir yıl için hesaplayabilmesi için "Ürünler" tablosuna geçebilmesi lazım.

Ürünler ve Satışlar arasındaki ilişkiyi çift tıklayıp ilişkinin yönünü "Cross Filter Direction" seçeneğinden "Both" olarak değiştiriyorum.

Bunu yaptığımda ilişkinin yönünü gösteren ok işareti çift yönlü hale geliyor.

Ve daha önce Ürünler tablosuna geçemediği için tüm Ürün ID'lerini sayan "Ürün Sayısı" metriği, bu sefer her bir yıl için Ürünler tablosunu filtreleyebilir hale geliyor. Bu özelliğin adı : Cross Filtering, Çapraz Filtreleme.

Aralarında çift yönlü (bidirectional) ilişki olan tablolarda, tablolardan herhangi biri filtrelendiğinde diğeri de filtrelenir. Yani, filtreler çift yönlü akar.

Cross filtering, Power BI ve SSAS'te var, PowerPivot'ta ise doğrudan yok. Tablolar arasındaki ilişki  tek yönlü tanımlanmış olsa bile , DAX komutu kullanarak  "geçici"  çift yönlü ilişki tanımlamak mümkün.

Ürün Sayısı CrossFilter :=
CALCULATE (
    COUNTROWS ( 'Ürünler' );
    CROSSFILTER ( 'Ürünler'[Ürün ID]; 'Satışlar'[Ürün ID]; BOTH )
)

Biraz önce yaptığımız çift yön değişikliğini tekrar eski haline, tek yönlü hale getiriyorum ve yukarıdaki metriği modele ekliyorum. Bu metrik hesaplanırken, "CrossFilter" komutu sayesinde "geçici olarak" Ürünler ve Satışlar tablosu arasında Ürün ID sütunu üzerinden çift yönlü ilişki kurmamı sağlıyor.

Biraz önceki matrise bu metriği de ekleyelim:


"Satış Yapılan Ürün Sayısı" ile "Ürün Sayısı CrossFilter" metrikleri her bir yıl için ve "total" satırında aynı rakamı gösteriyor. Çünkü her iki metrik de, Tarih tablosundan gelen yıl filtresini, Satışlar ve Ürünler tablosuna uygulayabiliyor. "Ürün Sayısı" ise ilişki artık tek yönlü olduğundan Tarih tablosundan akan yıl filtresini Ürünler tablosuna taşıyamadığından tüm ürünleri sayıyor.

Hazır örneği oluşmuşken küçük bir not: Total satırı Toplam satırı demek değildir. "Özet" satırıdır. Aynı diğer hücrelerde olduğu gibi, Total satırının her bir hücresi de ayrı ayrı hesaplanır. Tabular engine, yukarıda örneğini verdiğim benzer cümleleri kurarak hesaplar her bir Total hücresini.

İki tablo arasında aynı anda birden fazla ilişki olabilir. Fakat aynı anda ilişkilerden  sadece bir tanesi aktif olabilir .

"Satışlar" ve "Tarih" tabloları arasında Termin Tarihi-Tarih sütunları üzerinden bir ilişki daha oluşturduğumuzda, bu ilişki kesikli çizgiyle gösterilir. Çünkü hali hazırda iki tablo arasında daha önceden oluşturulmuş "aktif" bir ilişki vardır.


Aktif olan ilişkiyi değiştirmek için "Edit Relationship" menüsünü kullanabilirsiniz.


Veya, "UseRelationship" komutunu kullanarak, aktif olmayan bir ilişkiyi "geçici olarak" aktif hale getirebiliriz.

Satışlar Termine Göre :=
CALCULATE (
    SUM ( 'Satışlar'[Tutar] );
    USERELATIONSHIP ( Tarih[Tarih]; 'Satışlar'[Termin Tarihi] )
)

One-to-Many, veya Many-to-One'a ek olarak PBI'da one-to-one yani bire-bir ilişki de tanımlanabilir. Bire-bir ilişkinin her iki yönündeki tablolar, tekil değerler içeren ortak sütun üzerinden birbirine bağlıdır. Bire-bir ilişkiye sahip iki tablo arasında filtrelerin akış yönü her zaman çift yönlüdür.

Yazıyı toparlamak gerekirse:

  • Tablolar arası ilişkiler veri modelinin temelidir, veri modelindeki tablolar arasında dolaşmamızı sağlar.
  • İlişki kurulan ortak sütun aynı veri tipinde olmalıdır.
  • İlişki, tek bir sütun üzerinden kurulur.
  • One tarafındaki tabloda bulunan sütun sadece tekil değerler içerebilir, duplike değerler olamaz.
  • One-to-Many ilişkilerde filtrenin akış yönü her zaman "one" tarafından "many" tarafınadır.
  • Tek taraflı akış Cross Filtering ile -veya Dax ile- çift yönlü yapılabilir. Bu durumda filtreler her iki yönde de akar.
  • İki tablo arasında birden fazla ilişki kurulabilir, fakat aynı anda sadece bir tanesi aktiftir, PBI, aksini belirtmedikçe aktif olan ilişkiyi kullanır.

Yazıda kullanılan modeli indirebilirsiniz;

Sadece kayıtlı üyeler görebilir. Giriş veya Üyelik için login.

Dipnot: Bi-directional filtering, cross filtering, ya da çapraz filtreleme, many-to-many tipindeki ilişkileri tanımlamak için de kullanılır. İlişki tipleri ile ilgili detaylı bir yazıya kadar, Power BI, one-to-many, one-to-one, many-to-one ve many-to-many tipindeki ilişkileri destekler diye not edebiliriz.

Yaklaşan Power BI Eğitimleri

Uçtan Uca Power BI,  17-18 Aralık
DAX ve Veri Modelleme, 24-25 Aralık