Raporlama sorgularında en sık ihtiyaç duyulan şeylerden biri, satırları gruplayıp kaybetmeden yanlarına hesaplama eklemektir: sıra numarası, önceki ayın değeri, kümülatif toplam, hareketli ortalama. GROUP BY satırları tek satıra indirir; pencere fonksiyonları (OVER ifadesi) ise her satırı korur. Bu yazıda en çok kullandığım dört kalıbı örnekliyorum.
Örnek tablo
CREATE TABLE dbo.AylikSatis (
Magaza varchar(20),
Ay date,
Tutar decimal(18,2)
);
INSERT INTO dbo.AylikSatis VALUES
('Merkez', '2026-01-01', 120000), ('Merkez', '2026-02-01', 135000),
('Merkez', '2026-03-01', 128000), ('Merkez', '2026-04-01', 150000),
('Sahil', '2026-01-01', 80000), ('Sahil', '2026-02-01', 76000),
('Sahil', '2026-03-01', 91000), ('Sahil', '2026-04-01', 99000);
1. Sıralama: ROW_NUMBER, RANK, DENSE_RANK
Her mağazanın en yüksek satış yaptığı ayı bulmak için satırları mağaza bazında numaralandırıp birinci olanı alırız:
WITH Sirali AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY Magaza ORDER BY Tutar DESC) AS Sira
FROM dbo.AylikSatis
)
SELECT Magaza, Ay, Tutar
FROM Sirali
WHERE Sira = 1;
ROW_NUMBER eşit değerlere de farklı numara verir. Eşitlerin aynı sırayı alması gerekiyorsa RANK (boşluk bırakır: 1,1,3) ya da DENSE_RANK (boşluk bırakmaz: 1,1,2) kullanın. Bu kalıp, tekrar eden kayıtları temizlerken (Sira > 1 olanları silmek) de çok işe yarar.
2. Önceki dönemle karşılaştırma: LAG
SELECT Magaza, Ay, Tutar,
LAG(Tutar) OVER (PARTITION BY Magaza ORDER BY Ay) AS OncekiAy,
Tutar - LAG(Tutar) OVER (PARTITION BY Magaza ORDER BY Ay) AS Fark
FROM dbo.AylikSatis
ORDER BY Magaza, Ay;
LAG bir önceki satırın değerini, LEAD bir sonrakini getirir. İkinci parametreyle kaç satır geri gidileceğini (LAG(Tutar, 12) ile geçen yılın aynı ayı gibi) belirtebilirsiniz. Self-join yazmaya gerek kalmaz.
3. Kümülatif toplam
SELECT Magaza, Ay, Tutar,
SUM(Tutar) OVER (
PARTITION BY Magaza
ORDER BY Ay
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS KumulatifToplam
FROM dbo.AylikSatis;
ROWS ifadesini açıkça yazmanızı öneririm. Yazmazsanız SQL Server varsayılan olarak RANGE kullanır; aynı tarihte birden fazla satır varsa sonuç beklediğinizden farklı olabilir ve performans da genellikle daha düşüktür.
4. Hareketli ortalama
SELECT Magaza, Ay, Tutar,
AVG(Tutar) OVER (
PARTITION BY Magaza
ORDER BY Ay
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
) AS UcAylikOrtalama
FROM dbo.AylikSatis;
Çerçeveyi (frame) değiştirerek 7 günlük, 12 aylık gibi istediğiniz pencereyi kurabilirsiniz. Mevsimsel dalgalanmaları yumuşatmak için raporlarda sık kullanılır.
Performans notları
PARTITION BYveORDER BYsütunlarına uygun bir indeks (örneğin(Magaza, Ay) INCLUDE (Tutar)) sıralama maliyetini ciddi şekilde düşürür.- Pencere fonksiyonları
WHEREiçinde doğrudan kullanılamaz; yukarıdaki gibi bir CTE ya da alt sorgu ile sarmalayın. - Aynı
OVERtanımını tekrar tekrar yazmak yerine SQL Server 2022 ve sonrasındaWINDOWifadesiyle pencereye isim verebilir, gerektiğinde çerçeveyi ekleyerek genişletebilirsiniz. (LAGgibi fonksiyonlar çerçeve kabul etmediği için isimli pencereye çerçeveyi koymayın.)
-- SQL Server 2022+
SELECT Magaza, Ay, Tutar,
LAG(Tutar) OVER w AS OncekiAy,
SUM(Tutar) OVER (w ROWS UNBOUNDED PRECEDING) AS Kumulatif
FROM dbo.AylikSatis
WINDOW w AS (PARTITION BY Magaza ORDER BY Ay);
Sık yapılan hatalar
- Eşitlikte belirsiz sıralama:
ORDER BYsütununda eşit değerler varsaROW_NUMBERher çalıştırmada farklı satırı birinci seçebilir. Sonucun tutarlı olması için sıralamaya benzersiz bir sütun (örneğin bir kimlik) ekleyin. - LAST_VALUE tuzağı: Çerçeve belirtilmezse varsayılan çerçeve geçerli satırda biter; bu yüzden
LAST_VALUEçoğu zaman satırın kendi değerini döndürür.ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWINGyazın. - LAG’in ilk satırda NULL döndürmesi: Önceki satır olmadığında sonuç
NULLolur. Üçüncü parametreyle varsayılan değer verebilirsiniz:LAG(Tutar, 1, 0). - Eksik ayları fark etmemek:
LAGbir önceki satırı getirir, bir önceki ayı değil. Bir ay hiç satış yoksa karşılaştırma kayar; önce bir tarih tablosuyla boşlukları doldurun.
Sık sorulan sorular
Pencere fonksiyonu mu, GROUP BY mı?
Satır başına tek bir özet yeterliyse GROUP BY. Hem satırın kendisini hem de grup bazlı bir hesabı (sıra, toplam payı, önceki değer) aynı satırda görmek istiyorsanız pencere fonksiyonu.
Veriyi eşit gruplara bölmek için ne kullanılır?
NTILE(4) OVER (ORDER BY Tutar DESC) satırları dört eşit gruba ayırır; mağazaları ya da ürünleri çeyreklik dilimlere ayırmak için pratiktir.
İlgili yazılar
- Power BI’da Tarih Tablosu: Neden Şart, Nasıl Kurulur?
- T-SQL’de INTERSECT ve EXCEPT Kullanımı
- Python ile Sorumlu Web Kazıma: Fiyat Takibi İçin Sağlam Bir Başlangıç
HABERDAR OL
Yeni rehberler, kategorilere ayrılmış tek bir e-postada.
Her pazartesi, o hafta yayımlanan yazılar konu başlıklarına göre derlenmiş olarak gelen kutunda. Yeni yazı yoksa e-posta da yok.

2 yorum