Tüm yazılarPerSight Ekibi · Son güncelleme: 23 Temmuz 2026 · 7 dk okuma

SQL GROUP BY: Gruplayıp Toplamayı Anlamak

Aylık ciro, müşteri başına sipariş, kategoriye göre adet: GROUP BY ile toplama. COUNT/SUM/AVG, WHERE ile HAVING farkı ve MySQL'in ONLY_FULL_GROUP_BY tuzağı, gerçek örneklerle.

"Hangi ay ne kadar sattık?" ya da "müşteri başına kaç sipariş düşüyor?" gibi sorular tek tek satırlarla değil, satır gruplarıyla ilgilenir. SQL'de satırları bir kolona göre öbekleyip her öbek için tek bir sayı üretmenin yolu GROUP BY'dır. Mantığını bir kez oturttuğunuzda raporların yarısı buradan çıkar.

GROUP BY tam olarak ne yapar?

GROUP BY, aynı değere sahip satırları tek bir gruba toplar; SELECT'teki toplama fonksiyonu (COUNT, SUM, AVG, MIN, MAX) da her grup için bir sonuç üretir. Kategoriye göre toplam adedi görelim:

SELECT kategori,
       COUNT(*) AS urun_sayisi,
       AVG(fiyat) AS ortalama_fiyat
FROM urunler
GROUP BY kategori
ORDER BY urun_sayisi DESC;

Altın kural: SELECT'te yer alan her kolon ya GROUP BY'da olmalı ya da bir toplama fonksiyonunun içinde. Aksi halde veritabanı "bu kolonun grup içinde hangi değerini basayım?" diye takılır.

WHERE ile HAVING arasındaki fark nedir?

İkisi de filtreler, ama farklı anda. WHERE gruplama olmadan önce satırları eler; HAVING gruplama sonrasında grupları eler. "En az beş sipariş vermiş müşteriler" gibi bir koşul ancak gruplama sonrası bilindiği için HAVING'e girer:

SELECT musteri_id, COUNT(*) AS siparis_sayisi
FROM siparisler
WHERE tarih >= DATE '2026-01-01'
GROUP BY musteri_id
HAVING COUNT(*) >= 5;
SQL Server DATE literalini tanımaz; orada tarihi düz metin (2026-01-01) olarak yazın.

Sıralamaya dikkat: önce WHERE (2026'dan önceki siparişleri at), sonra GROUP BY (müşteriye göre öbekle), en son HAVING (beşten az sipariş vereni ele). Bu sırayı bilmek çoğu "neden yanlış sonuç geliyor?" sorusunu ortadan kaldırır.

Birden fazla kolona göre gruplama

GROUP BY'a birden çok kolon verebilirsiniz; gruplar bu kolonların kombinasyonuna göre oluşur. Yıl ve aya göre ciro klasik örnektir:

SELECT EXTRACT(YEAR FROM tarih)  AS yil,
       EXTRACT(MONTH FROM tarih) AS ay,
       SUM(tutar) AS ciro
FROM siparisler
GROUP BY EXTRACT(YEAR FROM tarih), EXTRACT(MONTH FROM tarih)
ORDER BY yil, ay;
PostgreSQL / Oracle. SQL Server'da YEAR(tarih), MONTH(tarih); MySQL'de de aynı.

Veritabanına göre neye dikkat etmeli?

En sık kafa karıştıran nokta MySQL'dir: ONLY_FULL_GROUP_BY modu kapalıysa MySQL, GROUP BY'da olmayan bir kolonu şikayet etmeden basar ve rastgele bir değer döndürür. Sessiz ve tehlikeli. Modern MySQL sürümlerinde bu mod açık gelir; açık tutun. PostgreSQL, SQL Server ve Oracle bu durumda zaten hata verir, bu yüzden sizi yanlıştan korur.

Sık sorulan sorular

GROUP BY ile DISTINCT arasındaki fark nedir?
DISTINCT yalnızca yinelenen satırları tekilleştirir; GROUP BY ise grupları oluşturup her grup için toplama (SUM, COUNT gibi) yapmanıza izin verir. Sadece benzersiz değer listesi istiyorsanız DISTINCT yeter; grup başına bir sayı üretecekseniz GROUP BY gerekir.
COUNT(*) ile COUNT(kolon) aynı şey mi?
Hayır. COUNT(*) gruptaki tüm satırları sayar; COUNT(kolon) o kolonun NULL olmayan değerlerini sayar. NULL içeren bir kolonda ikisi farklı sonuç verir.
Toplama yaparken NULL değerler ne olur?
SUM, AVG ve COUNT(kolon) gibi fonksiyonlar NULL'ları yok sayar. Özellikle AVG'de bu önemlidir: NULL'lar ortalamaya sıfır olarak değil, hiç katılmaz. Sıfır saymasını istiyorsanız COALESCE ile NULL'ı 0'a çevirmelisiniz.
Grupları sonuç sayısına göre sıralayabilir miyim?
Evet. ORDER BY'da toplama fonksiyonunu ya da ona verdiğiniz takma adı kullanın; örneğin ORDER BY SUM(tutar) DESC ile en çok satan grubu en üste alırsınız.

Aynı raporu SQL yazmadan istiyorsanız PerSight'a "2026 cirosunu aya göre göster" ya da "en az beş sipariş vermiş müşterileri getir" demeniz yeterli. Sonucu tablo ve grafik olarak önünüze koyar, arkasındaki GROUP BY sorgusunu da açıkça gösterir.

Kaynaklar