Ana içeriğe geç
Kesit Power BI
Orta · Veri Hazırlama

Power BI analisti için SQL: kaynağı sorgulamak ve DAX ile karşılaştırmak

İş ilanlarının neredeyse hepsi Power BI’ın yanında SQL ister. SELECT, WHERE, JOIN, GROUP BY ve HAVING’i bu uygulamanın tablolarıyla öğren, aynı soruyu SQL ve DAX ile yan yana cevapla, işin SQL görünümünde mi, Power Query’de mi, DAX’ta mı yapılacağına karar ver.

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

Anadolu Market’te bir analistin SQL’e üç yerde ihtiyacı olur: kaynağı tanımak (bu tabloda ne var, kaç satır var?), rakamı doğrulamak (rapordaki toplam veritabanıyla tutuyor mu?) ve veriyi hazırlamak (veritabanı ekibiyle birlikte bir görünüm yazmak). Power BI’a bağlanmadan önce birkaç satır SQL, modelde saatlerce aranacak bir sorunu baştan gösterir. Bu derste örnekler, uygulamanın modelindeki tabloların bir veritabanında aynı adla durduğunu varsayar: Satislar, Urunler, Musteriler.

Aynı veri, iki farklı düşünme biçimi

SQLDAX
Nerede çalışır?Kaynak veritabanındaPower BI anlam modelinde
Tabloları nasıl bağlar?Her sorguda JOIN ile açıkçaModeldeki ilişkiler üzerinden, kendiliğinden
Filtre nereden gelir?Sorgunun WHERE koşulundanGörselden, dilimleyiciden ve CALCULATE’ten (filtre bağlamı)
SonuçBir kez hesaplanan sabit bir tabloHer hücrede yeniden hesaplanan bir ölçü

Bu farkın en önemli sonucu şudur: SQL’de “kategoriye göre satış” için bir sorgu, “yıla göre satış” için başka bir sorgu yazarsın. DAX’ta tek bir [Net Satış] ölçüsü her iki görselde de doğru çalışır.

SELECT ve WHERE: satırları seçmek

-- 2024’te Mağaza kanalında iptal olmayan satışların toplamı
SELECT SUM(s.Tutar) AS NetSatis
FROM   Satislar AS s
WHERE  s.Kanal = N'Mağaza'
  AND  s.Durum <> N'İptal'
  AND  s.Tarih >= '2024-01-01' AND s.Tarih < '2025-01-01';

Aynı soru DAX’ta bir ölçüyle ve tarihin görselden gelmesiyle cevaplanır:

Mağaza Net Satış (2024) =
CALCULATE([Net Satış], Satislar[Kanal] = "Mağaza", Tarih[Yil] = 2024)

İkisi de 123.997,10 ₺ döner. Ayrıntılar:

JOIN: ilişkiyi sorguda kurmak

SELECT u.Kategori, SUM(s.Tutar) AS NetSatis
FROM   Satislar AS s
JOIN   Urunler  AS u ON u.UrunNo = s.UrunNo
WHERE  s.Durum <> N'İptal'
GROUP BY u.Kategori
ORDER BY NetSatis DESC;

DAX karşılığında JOIN yok, çünkü Satislar ile Urunler arasındaki ilişki modelde zaten var:

EVALUATE
SUMMARIZECOLUMNS(Urunler[Kategori], "Net Satış", [Net Satış])
ORDER BY [Net Satış] DESC

Elektronik 339.303,65 ₺ ile ilk sırada, Hediye 17.370 ₺ ile son sırada. JOIN türü önemlidir: JOIN (INNER) yalnızca iki tarafta da eşleşen satırları getirir, LEFT JOIN soldaki tablonun tüm satırlarını tutar. “Hiç alışveriş yapmamış müşteri” sorusu bu yüzden LEFT JOIN ister: Musteriler tablosundaki 150 müşterinin 14’ünün hiç satış satırı yok. Power Query’deki birleştirme türleri de aynı mantıkla çalışır (“Power Query: join türleri, dizin sütunu ve gruplu sıra” dersi).

GROUP BY ve HAVING: gruplamak ve grubu süzmek

WHERE gruplamadan önce satırları, HAVING gruplamadan sonra grupları süzer. “Net satışı 180.000 ₺’yi aşan kategoriler”:

SELECT u.Kategori, SUM(s.Tutar) AS NetSatis
FROM   Satislar AS s
JOIN   Urunler  AS u ON u.UrunNo = s.UrunNo
WHERE  s.Durum <> N'İptal'
GROUP BY u.Kategori
HAVING SUM(s.Tutar) > 180000;
EVALUATE
FILTER(
    SUMMARIZECOLUMNS(Urunler[Kategori], "Net", [Net Satış]),
    [Net] > 180000
)

Dört kategori döner: Elektronik, Ev & Yaşam, Giyim, Spor (184.231,10 ₺). HAVING’in DAX’taki karşılığı, özet tablonun üzerine konan FILTER’dır.

Ada göre değil, anahtara göre gruplaMusteriler tablosunda 150 müşteri var ama yalnızca 140 farklı ad: 10 ad iki farklı kişiye ait. GROUP BY Musteri yazarsan iki “Kaan Kara” tek satırda birleşir ve 32 sipariş görünür; 49 numaralı Kaan Kara’nın kendi sipariş sayısı 18. Her zaman anahtarla (MusteriNo) grupla, adı yalnızca etiket olarak ekle. Aynı tuzak DAX’ta da vardır: görsele Musteriler[Musteri] koyarsan iki kişi tek satır olur.

COUNT(DISTINCT …) da toplanabilir değildir. Kategorilere göre farklı sipariş sayılarını toplarsan 1.377 eder; gerçek sipariş sayısı 838’dir, çünkü bir sipariş birden çok kategoride ürün içerebilir. SQL’de de DAX’ta da toplam, alt toplamların toplamı olmayabilir.

İş nerede yapılmalı: SQL görünümü, Power Query, DAX

Yaygın bir kural (Roche’un ilkesi olarak bilinir): veri dönüşümünü olabildiğince yukarıda, gerektiği kadar aşağıda yap.

Nerede?Ne için uygun?Anadolu Market örneği
SQL görünümü (view)Birçok raporun kullanacağı, kurumsal kurala bağlı temizlik ve birleştirme. Veritabanı ekibi bakımını üstlenir.Test siparişlerini dışlayan vw_Satislar görünümü
Power QueryKaynağa yazma iznin olmadığında şekillendirme; Excel ve SharePoint gibi veritabanı olmayan kaynaklar.Bayi Excel dosyasındaki başlık satırlarını temizlemek
DAX ölçüsüFiltreye göre değişmesi gereken her hesap: oranlar, zaman karşılaştırmaları, paylar.[MoM %], [Kategori Payı %]

Kural basit: satır düzeyinde ve sabit olan iş kaynağa ya da Power Query’ye, filtreye göre değişen iş DAX’a. Kategori payını SQL’de sabit bir sütun olarak hesaplarsan, kullanıcı dilimleyiciden bir yıl seçtiğinde pay yanlış kalır.

Sorgu katlama ve yerel sorgu riskleri

Power Query, gezginden seçtiğin bir tabloda yaptığın filtre ve gruplama adımlarını çoğu zaman kendisi SQL’e çevirip veritabanına gönderir; buna sorgu katlama (query folding) denir. Gezgin ile yerel SQL sorgusu arasındaki seçimi ve katlamayı korumanın yolunu “Veri bağlantıları: veritabanı, yerel SQL sorgusu, Desktop ile Service” dersinde gördük; katlamanın temelleri “Power Query: birleştirme, ekleme, özetten çıkarma” dersinde. Burada yalnızca analistin bilmesi gereken riskleri toplayalım:

Rakamı SQL ile doğrulamak

Bir raporu yayımlamadan önce veritabanında üç sorgu çalıştırıp sonucu modeldeki karşılığıyla eşleştirmek iyi bir alışkanlıktır: satır sayısı (COUNT(*)), ham tutar toplamı (SUM(Tutar)) ve yıla göre kırılım. Modeldeki karşılığı ve mutabakatın tamamı “Rapor kalitesi: veri mutabakatı, ölçü testleri, belgeleme ve kabul testi” dersinde.

SELECT YEAR(Tarih) AS Yil, COUNT(*) AS Satir, SUM(Tutar) AS HamTutar
FROM   Satislar
GROUP BY YEAR(Tarih)
ORDER BY Yil;
Daha fazla SQL için Kesit SQLBu uygulamanın kardeşi Kesit SQL’de aynı sipariş verisiyle SELECT’ten pencere fonksiyonlarına kadar SQL alıştırmaları var. Mülakatlarda en sık istenen konular: JOIN türleri, GROUP BY ile HAVING farkı, alt sorgu ve CTE, ROW_NUMBER gibi pencere fonksiyonları.
Alıştırmalara geç (7)