“İleri iş kalıpları” dersinde Top N + Diğer, sepet analizi, ürün düzeyinde LFL ve aylık kurla dönüşümün iskeletini kurdun; Measure Lab’de [Yoldaki Sipariş] kalıbını gördün. Bu ders o kalıpları üretime taşıyor: gerçek verinin kenar durumları, aynı sorunun iki farklı doğru tanımı ve raporu sessizce bozan tanecik farkları. Her bölümde önce mevcut çözümün nerede yanlış sayı verdiğini motorla göreceğiz.
1 · Devam eden olaylar: açık siparişleri doğru saymak
Lojistik müdürü yılbaşı sabahı soruyor: “31 Aralık 2024 akşamı depoda kaç açık sipariş vardı?” Measure Lab’deki [Yoldaki Sipariş], ay satırlarında 2024 boyunca 1 ile 5 arasında değerler veriyor. Aralık 2024 satırı ise BLANK.
Sebep veride: Aralık’ın son günlerinde verilmiş 6 sipariş (10 satır) hâlâ “Kargoda” ve TeslimTarihi boş. Kalıp Satislar[TeslimTarihi] > Gun koşulunu kullanıyor; DAX’ta BLANK bir tarihle karşılaştırılınca sıfır gibi davranır ve koşul yanlış olur. Yani “henüz teslim edilmemiş” siparişler, tam da sayılması gerekenler, dışarıda kalıyor. Öte yandan iptal edilen 121 satırın da teslim tarihi boş; onları açık saymamalıyız.
Açık Sipariş =
VAR Gun = MAX(Tarih[Tarih])
RETURN
CALCULATE(
DISTINCTCOUNT(Satislar[SiparisNo]),
REMOVEFILTERS(Tarih),
Satislar[Tarih] <= Gun,
Satislar[Durum] <> "İptal",
FILTER(
ALL(Satislar[TeslimTarihi]),
ISBLANK(Satislar[TeslimTarihi]) || Satislar[TeslimTarihi] > Gun
)
)
| Ay sonu | [Yoldaki Sipariş] | [Açık Sipariş] |
|---|---|---|
| 2024-10 | 5 | 5 |
| 2024-11 | 3 | 3 |
| 2024-12 | BLANK | 6 |
Geçmiş aylar aynı, çünkü o siparişlerin teslim tarihi artık dolu. Hata yalnızca en güncel dönemde, yani yöneticinin en çok baktığı yerde görünür. Devam eden olay kalıbının genel kuralı: bitiş tarihi boşsa olay hâlâ sürüyordur; iptal gibi “hiç başlamamış” durumları ayrıca dışla.
Aynı kalıptan türeyen üç soru
| Soru | Değişiklik | 31.12.2024 |
|---|---|---|
| Açık sipariş tutarı | DISTINCTCOUNT yerine SUM(Satislar[Tutar]) | 11.063 ₺ |
| 3 günden uzun açık (yaşlandırma) | Satislar[Tarih] <= Gun - 3 | 2 sipariş |
| Ay içinde ortalama günlük açık sipariş | AVERAGEX(VALUES(Tarih[Tarih]), [Açık Sipariş]) | Aralık: 6,2 · en yüksek gün: 10 |
Ay sonu değeri (6) ile ayın günlük ortalaması (6,2) ve zirvesi (10) farklı kararlar doğurur: ay sonu bilanço içindir, ortalama kapasite planı içindir, zirve ise vardiya planı içindir. Raporda hangisini gösterdiğini başlıkta yaz.
Performans: dinamik ölçü mü, fotoğraf tablosu mu?
| Yol | Ne zaman? | Bedel |
|---|---|---|
| Dinamik ölçü (yukarıdaki) | Ay ya da gün düzeyinde, orta büyüklükte olgu | Her hücrede tarih filtresi yeniden kurulur; günlük ortalamada gün sayısı × sorgu |
| Günlük fotoğraf tablosu (Tarih × açık sipariş sayısı) | Milyonlarca satır, günlük trend sık kullanılıyor | Yenilemede hesaplanır (Power Query ya da ambar); geçmişe dönük düzeltmelerde yeniden üretmek gerekir |
StokGorunum tablosu da bir fotoğraf tablosudur; “Model tasarımı II” dersinde gördüğün gibi aylar boyunca toplanmaz, son değeri alınır. Açık sipariş de aynı türde, yarı toplanabilir bir ölçüdür: yıl satırında 12 ayın toplamı değil, yıl sonu değeri gösterilir.
2 · Karşılaştırılabilir dönem: hangi müşteriler “aynı”?
“İleri iş kalıpları” dersinde LFL’yi ürün kümesiyle kurdun: her iki dönemde de satılan ürünler. Aynı fikri müşteriye uyguladığında, ürün analizinde göze batmayan bir tuzak ortaya çıkar. Yönetim kurulu soruyor: “2024’teki %86 büyümenin ne kadarı yeni müşteriden, ne kadarı mevcut müşterinin daha çok harcamasından?”
| Tanım | Küme | 2024 / 2023 | Büyüme |
|---|---|---|---|
| Tüm müşteriler | Herkes | 747.066 / 400.870 ₺ | +%86,4 |
| Etkinliğe göre (her iki yılda alan) | 64 müşteri | — | +%27,3 |
| Kohorta göre (ilk siparişi 2023’ten önce) | 46 müşteri | 194.668 / 202.047 ₺ | −%3,7 |
İki “karşılaştırılabilir” tanım, işareti bile farklı iki sonuç veriyor. Etkinliğe dayalı tanım, 2024’te alışverişi bırakan müşterileri tanım gereği dışarıda bırakır: yalnızca “hayatta kalanlar” kalır. Bu hayatta kalan yanlılığı (survivorship bias) mevcut müşteri büyümesini olduğundan iyi gösterir. Kohort tanımı ise kümeyi dönem başında, sonuca bakmadan sabitler; kayıpları da içerir. Eski müşteri tabanı aslında küçülmüş; büyümenin tamamı yeni müşterilerden geliyor.
Eski Kohort Satışı =
VAR DonemBasi = MIN(Tarih[Tarih])
VAR KarsilastirmaBasi = EDATE(DonemBasi, -12)
VAR EskiMusteriler =
CALCULATETABLE(
VALUES(Musteriler[MusteriNo]),
REMOVEFILTERS(Tarih),
Musteriler[IlkSiparis] < KarsilastirmaBasi
)
RETURN
CALCULATE([Net Satış], EskiMusteriler)
Eski Kohort Satışı GY =
VAR DonemBasi = MIN(Tarih[Tarih])
VAR KarsilastirmaBasi = EDATE(DonemBasi, -12)
VAR EskiMusteriler =
CALCULATETABLE(
VALUES(Musteriler[MusteriNo]),
REMOVEFILTERS(Tarih),
Musteriler[IlkSiparis] < KarsilastirmaBasi
)
RETURN
CALCULATE([Net Satış], EskiMusteriler, SAMEPERIODLASTYEAR(Tarih[Tarih]))
Küme, karşılaştırma döneminin başına göre kurulur: 2024 satırında “ilk siparişi 1 Ocak 2023’ten önce olanlar”. Böylece aynı 46 müşteri iki yılda da ölçülür.
Kenar durumlar
- Eksik taban yılı: Veri Haziran 2022’de başlıyor. 2023’ün 2022’ye göre büyümesi (+%290) yarım yılı tam yılla karşılaştırır; 2023 satırında LFL’yi gizle ya da yalnızca ortak aylarla hesapla.
- Bölme biçimi:
DIVIDE(A, B) - 1taban boşken BLANK − 1 = −1 verir; 2022 satırı “−%100” görünür.DIVIDE(A - B, B)boş döner. - Tanımı belgele: Ölçü adına tanımı koy (“Eski Kohort Büyümesi”), açıklamaya kümenin nasıl seçildiğini yaz. “LFL” kısaltması tek başına iki ayrı ekipte iki ayrı şey demektir.
3 · Döviz çevirme: hangi kur, hangi sayı?
Ortaklara dolar bazlı rapor hazırlanıyor. Kur tablosu DovizKurlari ayda bir satır tutuyor (ayın ilk günü, USD ve EUR) ve Tarih’e bağlı değil. Aylık kurla satış dönüşümünü Measure Lab’deki [Satış (Seçili Para)] yapıyor. Uzman sorusu şu: her sayı aynı kurla mı çevrilir?
| Sayı türü | Örnek | Doğru kur |
|---|---|---|
| Akış (dönem boyunca oluşur) | Satış, gider, satın alma | İşlem tarihinin kuru (burada ay kuru); ay ay çevrilip toplanır |
| Bakiye (bir andaki fotoğraf) | Stok değeri, açık sipariş tutarı, alacak | Dönem sonu kuru |
| Performans karşılaştırması | Büyüme, hedef sapması | Sabit kur (iki dönem aynı kurla) |
Akış ve bakiye
2024 net satışı 747.066 ₺. Aylık kurlarla 22.614 $; tüm yılı Aralık kuruyla (35,00) çevirirsen 21.345 $; yıl ortalama kuruyla (32,78) 22.788 $. Akış için doğru olan ilkidir. Stok değeri ise yıl sonu fotoğrafıdır: 163.465 ₺, dönem sonu kuruyla 4.670 $. Ortalama kurla çevirmek 4.986 $ verir ve bilançoda olmayan bir değeri raporlar.
Stok Değeri (USD, Dönem Sonu) =
VAR SonAyBasi = EOMONTH(MAX(Tarih[Tarih]), -1) + 1
VAR Kur =
LOOKUPVALUE(DovizKurlari[Kur], DovizKurlari[Tarih], SonAyBasi, DovizKurlari[ParaBirimi], "USD")
RETURN
DIVIDE([Stok Değeri], Kur)
Sabit kur: büyümenin ne kadarı kurdan?
Dolar bazında 2024 büyümesi 22.614 / 16.613 → +%36,1. TL bazında +%86,4. Hangisi “gerçek” performans? İkisini ayırmak için 2024’ün her ayını, 2023’ün aynı ayının kuruyla çevir:
Satış USD (GY Kuruyla) =
SUMX(
VALUES(Tarih[YilAy]),
VAR GecenYilAyBasi = EDATE(DATEVALUE(Tarih[YilAy] & "-01"), -12)
VAR Kur =
LOOKUPVALUE(DovizKurlari[Kur], DovizKurlari[Tarih], GecenYilAyBasi, DovizKurlari[ParaBirimi], "USD")
RETURN DIVIDE([Net Satış], Kur)
)
2024 sabit kurla 31.204 $; 2023’e göre +%87,8. Yani iş hacmi neredeyse ikiye katlanmış, TL’nin değer kaybı dolar büyümesini %36’ya indirmiş. Kur etkisi: 22.614 − 31.204 = −8.590 $. Bu ayrıştırma, “dolar büyümesi düşük, ekip başarısız” yanlış sonucunu önler.
Eksik kur: sessiz kayıp
Yukarıdaki ölçü 2022 satırında BLANK verir; kur tablosunda 2021 yok. Asıl tehlike toplam satırında: 54.948 $, 2022’yi hiç içermiyor ve hiçbir uyarı yok. Üretimde iki koruma kur:
- Kontrol ölçüsü: görünen aylardan kuru bulunamayanları say; sıfırdan büyükse kartta uyarı göster.
- Son bilinen kur: kur tablosu bir gün geç yükleniyorsa, “o tarihe kadar bilinen en son kur” mantığı (MAX(DovizKurlari[Tarih]) ≤ gün) boş ay yerine bir önceki ayın kurunu kullanır. Bunu yalnızca iş birimi onaylarsa yap ve açıklamaya yaz.
Kuru Eksik Ay =
COUNTROWS(
FILTER(
VALUES(Tarih[YilAy]),
ISBLANK(
LOOKUPVALUE(DovizKurlari[Kur], DovizKurlari[Tarih], EDATE(DATEVALUE(Tarih[YilAy] & "-01"), -12), DovizKurlari[ParaBirimi], "USD")
)
)
)
2022 satırında 12, diğer yıllarda BLANK döner. Toplam satırında da 12: rapor kullanıcısına “bu toplamın 12 ayı eksik” demenin tek yolu budur.
4 · Farklı taneciklikte bütçe: aylık hedefi güne dağıtmak
Satış direktörü haftalık toplantı için “haftalık satış ve hedef” tablosu istiyor. Hedefler ay düzeyinde ve her ayın hedefi ayın 1. gününe yazılı. Hafta kırılımında [Hedef] şöyle görünür:
| 2024 haftası | Net satış | [Hedef] | Günlük dağıtım |
|---|---|---|---|
| 1 (1–7 Ocak, 30–31 Aralık) | 27.516 ₺ | 48.500 ₺ | 16.655 ₺ |
| 2 | 6.921 ₺ | BLANK | 10.952 ₺ |
| 5 (29 Ocak–4 Şubat) | 5.682 ₺ | 46.000 ₺ | 11.038 ₺ |
Ayın 1’ini içeren hafta ayın bütün hedefini alıyor, diğer haftalar hedefsiz. Aynı sorun ay içi “bugüne kadar” raporunda daha da tehlikeli: 1–15 Aralık 2024 satışı 60.134 ₺, [Hedef] 88.400 ₺ gösteriyor ve ekip “%68’deyiz” diye alarm veriyor. Günlük dağıtımla hedef 42.774 ₺, gerçekleşme %141. 2–31 Aralık seçilirse hedef BLANK olur.
Hedef (Günlük Dağıtım) =
SUMX(
VALUES(Tarih[YilAy]),
VAR Ay = Tarih[YilAy]
VAR AyHedefi = CALCULATE([Hedef], REMOVEFILTERS(Tarih), Tarih[YilAy] = Ay)
VAR AyGunSayisi = CALCULATE(COUNTROWS(Tarih), REMOVEFILTERS(Tarih), Tarih[YilAy] = Ay)
VAR GorunenGun = CALCULATE(COUNTROWS(Tarih))
RETURN DIVIDE(AyHedefi * GorunenGun, AyGunSayisi)
)
Her görünen ay için: ayın tam hedefi × (görünen gün / ayın gün sayısı). GorunenGun, bağlam geçişiyle o ayın görünen günlerini sayar; hafta 1’de Ocak için 7, Aralık için 2. Ay ve yıl satırlarında sonuç [Hedef] ile birebir aynıdır (2024: 763.200 ₺), yani ölçü mevcut raporları bozmaz.
Tarih[YilAy] = Ay yerine VALUES(Tarih[YilAy]) yazarsan, “Genişletilmiş tablolar” dersinde gördüğün gibi filtre argümanı dış bağlamda hesaplanır ve hafta 1’de iki ayı birden döndürür. Sonuç 16.655 ₺ yerine 19.873 ₺ olur. Ay, çeyrek ve yıl satırlarında ise iki sürüm aynı sayıyı verir; hata yalnızca ay sınırını kesen kırılımlarda görünür. Testte mutlaka hafta ve “1–15 Aralık” gibi kısmi bir aralık dene.Üç strateji
| Strateji | Ne yapar? | Ne zaman? |
|---|---|---|
| Dağıt (yukarıdaki) | Ay hedefini görünen günlere orantılar | Haftalık ve ay içi takip isteniyorsa |
| Gizle | Görünen gün sayısı, görünen ayların tam gün sayısına eşit değilse BLANK | Hedef ancak ay düzeyinde anlamlıysa; yanlış sayı göstermektense boş |
| Önceden dağıt | Power Query’de ya da ambarda gün düzeyinde hedef tablosu | Büyük model, ağırlıklı dağıtım (iş günü, mevsimsellik) |
Hedef (Yalnızca Tam Ay) = VAR GorunenGun = COUNTROWS(Tarih) VAR TamAyGun = CALCULATE(COUNTROWS(Tarih), REMOVEFILTERS(Tarih), VALUES(Tarih[YilAy])) RETURN IF(GorunenGun = TamAyGun, [Hedef])
Burada VALUES doğru kullanım: ölçü iteratör içinde değil, dış bağlamda tek bir kez hesaplanıyor. Eşit dağıtım bir varsayımdır: hafta sonu satışı yüksek bir perakendecide günlere eşit pay vermek hafta içini hep “geride” gösterir. “Zaman serisi analizi” dersindeki haftanın günü endeksiyle ağırlıklandırmak bir sonraki adımdır; bu durumda önceden dağıtılmış gün tablosu daha bakımı kolay olur. Aynı kalıp GiderButce için de geçerlidir: gider bütçesi gider türü × ay düzeyinde, günlük dağıtım ölçüsü gider türü kırılımında [Gider Bütçe] ile aynı sayıyı verir.
Uzman kalıp kontrol listesi
- Bitiş tarihi boş olabilir mi? Devam eden olaylarda boş bitiş “sürüyor” demektir; iptal gibi başlamamış durumları ayrıca dışla.
- Ölçü toplanabilir mi? Açık sipariş ve stok gibi bakiyeler yıl boyunca toplanmaz; dönem sonu ya da ortalama göster, hangisi olduğunu başlığa yaz.
- Karşılaştırılabilir küme sonuca bakmadan mı seçildi? Etkinliğe dayalı küme hayatta kalan yanlılığı taşır.
- Sayı akış mı, bakiye mi? Akış işlem kuruyla, bakiye dönem sonu kuruyla; büyüme yorumu sabit kurla.
- Kur eksik mi? Kontrol ölçüsü toplam satırında da uyarmalı.
- Bütçe hangi tanecikte? Ay sınırını kesen her kırılımda (hafta, tarih aralığı) hedefin ne gösterdiğini test et; dağıt, gizle ya da önceden dağıt.
- Belgele: Her uzman ölçünün açıklamasına tanımı, kenar durumu ve test edilen kırılımları yaz. Bu ölçüler ekipte en çok “neden bu sayı?” sorusu alanlardır.