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
| SQL | DAX | |
|---|---|---|
| Nerede çalışır? | Kaynak veritabanında | Power BI anlam modelinde |
| Tabloları nasıl bağlar? | Her sorguda JOIN ile açıkça | Modeldeki ilişkiler üzerinden, kendiliğinden |
| Filtre nereden gelir? | Sorgunun WHERE koşulundan | Görselden, dilimleyiciden ve CALCULATE’ten (filtre bağlamı) |
| Sonuç | Bir kez hesaplanan sabit bir tablo | Her 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:
- N öneki: SQL Server’da Türkçe karakterli metinleri
N'İptal'biçiminde yaz. N, metnin Unicode olduğunu söyler; yoksa “İ” gibi harfler sütunun karakter kümesine göre bozulabilir ve eşleşme sessizce başarısız olur. - Tarih aralığı:
YEAR(Tarih) = 2024yerine aralık yazmak, veritabanının dizini kullanmasını sağlar. - Büyük-küçük harf: DAX metin karşılaştırmasında harf büyüklüğüne bakmaz; SQL’de bu, veritabanının harmanlama (collation) ayarına bağlıdır.
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.
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 Query | Kaynağ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:
- Katlama çoğu zaman biter: Yerel bir SQL sorgusundan sonra eklenen Power Query adımlarının kaynağa katlanması yalnızca bazı bağlayıcılarda mümkündür. Geri kalan adımlar bilgisayarında ya da ağ geçidinde çalışır ve yenileme yavaşlar.
- Yan etki riski: Microsoft Learn’e göre yerel sorguların amacı veriyi değiştirmemektir, ama Power Query bunun garantisini vermez. Bu yüzden Desktop, bağlayıcı penceresi dışında çalışan her yeni sorgu metni için onay ister (Seçenekler → Güvenlik → “Require user approval for new native database queries”). Başkasının yazdığı sorguyu senin kimlik bilgilerinle çalıştırmadan önce oku.
- DDL desteklenmez:
CREATE TABLE,DROP TABLE,ALTER TABLEgibi komutlar Power Query’de desteklenmez ve hataya yol açar. - Bakım: Rapora gömülü uzun bir SQL metnini başka kimse bulamaz. Tekrar kullanılacak mantığı veritabanında bir görünüme taşı ve bağlantı için yalnızca okuma izni olan bir hesap iste.
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;