SQL DISTINCT ve GROUP BY farkı, sorgunun sonunda nasıl bir çıktı istediğinle ilgilidir. Benzersiz müşteri listesi oluşturmak için genellikle SELECT DISTINCT kullanılır; müşteri başına sipariş sayısı gibi hesaplamalar gerektiğinde ise GROUP BY tercih edilir. Ancak doğru seçimi yapmadan önce, sorgu sonucundaki bir satırın neyi temsil ettiğini belirlemek gerekir.
Aşağıdaki örneklerde müşteriler ve siparişler tablolarını birlikte kullanacağız. Böylece JOIN sonrasında oluşan satırları inceleyip DISTINCT’in tekrarları nasıl kaldırdığını adım adım görebilirsiniz.
Önce Sonuç Satırının Ne Anlattığını Belirleyin
Bir SQL sorgusunu yazmadan önce şu soruyu sorun: Bir satır bir müşteri mi, bir sipariş mi, yoksa bir müşteri-kategori eşleşmesi mi? Bu sorunun cevabı, sorguda DISTINCT veya GROUP BY kullanıp kullanmayacağınızı doğrudan etkiler.
Örneğin musteriler tablosunda müşteriler, siparisler tablosunda ise her siparişin hangi müşteriye ait olduğu tutuluyor olsun:
| müşteri_id | müşteri_adı |
|---|---|
| 1 | Ayşe |
| 2 | Mehmet |
| 3 | Zeynep |
| sipariş_id | müşteri_id | kategori |
|---|---|---|
| 101 | 1 | Elektronik |
| 102 | 1 | Kitap |
| 103 | 2 | Kitap |
| 104 | 3 | Elektronik |
| 105 | 3 | Elektronik |
Bu iki tabloyu müşteri kimliği üzerinden birleştirelim:
SELECT
m.müşteri_id,
m.müşteri_adı,
s.sipariş_id,
s.kategori
FROM musteriler AS m
JOIN siparisler AS s
ON m.müşteri_id = s.müşteri_id;
Sonuçta beş satır elde edilir. Ayşe iki sipariş verdiği için iki satırda, Zeynep de iki sipariş verdiği için iki satırda görünür. Bu durum bir hata değildir; JOIN sonucundaki doğal satır düzeyi müşteri-sipariş düzeyidir.
| müşteri_adı | sipariş_id | kategori |
|---|---|---|
| Ayşe | 101 | Elektronik |
| Ayşe | 102 | Kitap |
| Mehmet | 103 | Kitap |
| Zeynep | 104 | Elektronik |
| Zeynep | 105 | Elektronik |
Kontrol noktası: Sorgunun satır düzeyi müşteri-sipariş ise beklenen satır sayısı, eşleşen sipariş sayısına yakın olur. Hedefiniz her müşteriyi yalnızca bir kez göstermekse sonuç düzeyini müşteri olarak yeniden düşünmeniz gerekir.
DISTINCT ile Benzersiz Müşteri Listesi Nasıl Oluşturulur?

JOIN sonucunda aynı müşterinin birden fazla kez görünmesini istemiyorsanız, müşteri bilgilerini seçerek DISTINCT kullanabilirsiniz:
SELECT DISTINCT
m.müşteri_id,
m.müşteri_adı
FROM musteriler AS m
JOIN siparisler AS s
ON m.müşteri_id = s.müşteri_id;
Bu sorgunun beklenen çıktısı üç satırdır:
| müşteri_id | müşteri_adı |
|---|---|
| 1 | Ayşe |
| 2 | Mehmet |
| 3 | Zeynep |
Burada DISTINCT, seçilen sütunların birlikte oluşturduğu aynı satır kombinasyonlarını tekilleştirir. Yalnızca m.müşteri_id seçilirse her kimlik bir kez görünür. Ancak müşteri kimliğinin yanına kategori eklerseniz sonuç artık müşteri-kategori kombinasyonlarını temsil eder. Örneğin Zeynep’in iki Elektronik siparişi yine tek satıra iner; fakat aynı müşterinin Kitap ve Elektronik siparişleri varsa iki farklı satır oluşur.
Bu nedenle DISTINCT toplama yapmaz, sipariş sayısını hesaplamaz ve gruplara değer üretmez. Yalnızca sonuç kümesindeki tekrar eden sütun kombinasyonlarını kaldırır. Sorgu sonuçlarını adım adım izleyerek öğrenmek isteyenler, uygulamalı video eğitimleri üzerinden bu tür sorguların çalışma mantığını tekrar tekrar inceleyebilir.
GROUP BY ile Müşteri Başına Sipariş Sayısını Hesaplayın
Her sonuç satırının bir müşteriyi temsil etmesini ve o müşterinin sipariş sayısını göstermesini istiyorsan GROUP BY kullanmalısın. Örneğin müşteri tablosunda Ada, Mert ve Selin; sipariş tablosunda ise bu müşterilere ait sırasıyla 3, 1 ve 2 sipariş bulunduğunu düşünelim.
SELECT
m.musteri_id,
m.musteri_adi,
COUNT(*) AS siparis_sayisi
FROM musteriler AS m
JOIN siparisler AS s
ON s.musteri_id = m.musteri_id
GROUP BY
m.musteri_id,
m.musteri_adi;
Beklenen çıktı şöyledir:
| musteri_id | musteri_adi | siparis_sayisi |
|---|---|---|
| 1 | Ada | 3 |
| 2 | Mert | 1 |
| 3 | Selin | 2 |
Burada GROUP BY, tekrar eden müşteri değerlerini yalnızca görünümden kaldırmaz. Aynı müşteriye ait sipariş satırlarını bir grup hâline getirir ve COUNT(*) ile her grup için bir hesaplama yapılmasını sağlar.
Yalnızca birden fazla siparişi bulunan müşterileri görmek için toplulaştırılmış sonuç HAVING ile filtrelenebilir:
SELECT
m.musteri_id,
m.musteri_adi,
COUNT(*) AS siparis_sayisi
FROM musteriler AS m
JOIN siparisler AS s
ON s.musteri_id = m.musteri_id
GROUP BY
m.musteri_id,
m.musteri_adi
HAVING COUNT(*) > 1;
Bu sorgu Ada ve Selin’i döndürür. WHERE, tek tek kayıtları gruplama işleminden önce filtreler. HAVING ise gruplar oluşturulup sipariş sayıları hesaplandıktan sonra sonucu filtreler. Dolayısıyla sipariş tarihi gibi satır düzeyindeki koşullar WHERE, “sipariş sayısı birden fazla olan müşteriler” gibi toplulaştırma koşulları HAVING bölümünde kullanılır.
COUNT(DISTINCT) Ne Zaman Gereklidir?

Bir sipariş, sipariş ürünleri tablosuyla birleştirildiğinde içerdiği her ürün satırı nedeniyle birden fazla kez görünebilir. Ada’nın verilerinin JOIN sonrasında şu şekilde oluştuğunu düşünelim:
| siparis_id | musteri_id | urun_id |
|---|---|---|
| 101 | 1 | 10 |
| 101 | 1 | 11 |
| 102 | 1 | 10 |
| 103 | 1 | 12 |
Bu tabloda dört kayıt vardır; ancak yalnızca üç benzersiz sipariş ve üç benzersiz ürün bulunur.
SELECT
musteri_id,
COUNT(*) AS toplam_satir,
COUNT(DISTINCT siparis_id) AS benzersiz_siparis,
COUNT(DISTINCT urun_id) AS benzersiz_urun
FROM siparis_urunleri
GROUP BY musteri_id;
Beklenen sonuç toplam_satir = 4, benzersiz_siparis = 3 ve benzersiz_urun = 3 olur. COUNT(*) JOIN sonucundaki bütün satırları sayarken COUNT(DISTINCT siparis_id) tekrarlanan sipariş kimliklerini bir kez sayar.
İki yapının görevi farklıdır: GROUP BY, müşteri başına ayrı bir sonuç satırı üretir; COUNT(DISTINCT sütun) ise her müşteri grubunda kaç farklı değer bulunduğunu ölçer. Bu nedenle önce sonucun hangi düzeyde üretileceğini, ardından satırların mı yoksa benzersiz değerlerin mi sayılacağını belirlemelisin.
DISTINCT, GROUP BY ve COUNT(DISTINCT) Kararını Çıktıyla Karşılaştırın
Aynı sipariş kayıtları üzerinde farklı bir sonuç granülerliği hedeflediğimizi düşünelim. Örnek veride Ayşe’nin üç, Bora’nın iki siparişi olsun. Ayşe iki farklı ürün kategorisinden, Bora ise yalnızca bir kategoriden sipariş vermiş olsun.
| Sorgunun amacı | Temel yaklaşım | Beklenen satır düzeyi | Örnek sonuç |
|---|---|---|---|
| Sipariş veren benzersiz müşterileri listelemek | SELECT DISTINCT musteri_id, musteri_adi |
Her müşteri için bir satır | Ayşe Bora |
| Müşteri başına sipariş sayısını bulmak | GROUP BY musteri_id, musteri_adi ve COUNT(*) |
Her müşteri için bir özet satırı | Ayşe: 3 Bora: 2 |
| Müşteri başına benzersiz kategori sayısını bulmak | COUNT(DISTINCT kategori) |
Her müşteri için bir özet satırı | Ayşe: 2 Bora: 1 |
DISTINCT ve GROUP BY, yalnızca müşteri sütunlarını seçtiğin basit sorgularda benzer sonuçlar üretebilir. Ancak doğru aracı belirleyen şey görünüş değil, sorgunun amacı ve sonuçtaki bir satırın neyi temsil edeceğidir.
Beş adımlı karar çerçevesi
- Beklenen satır düzeyini belirle: Sonuçta her sipariş mi, her müşteri mi, yoksa her müşteri-kategori eşleşmesi mi bir satır olmalı?
- Gerekli sütunları seç: Sonuçta kullanılmayacak sütunları sorguya ekleme. Çünkü
DISTINCT, seçilen sütunların tamamını bir kombinasyon olarak değerlendirir. - Yalnızca tekrarları kaldıracaksan
DISTINCTkullan: Amaç benzersiz müşteri listesi gibi tekilleştirilmiş kayıtlar üretmekse bu yaklaşım uygundur. - Grup başına hesap yapacaksan
GROUP BYkullan: Müşteri başına sipariş sayısı, toplam tutar veya ortalama değer gibi hesaplamalar gruplama gerektirir. - Bir sütunun benzersiz değerlerini sayacaksan
COUNT(DISTINCT)kullan: Toplam sipariş sayısı yerine müşterinin kaç farklı kategoriden alışveriş yaptığını ölçmek buna örnektir.
Beklenmeyen Sonuçları Teşhis Etmek İçin SQL Kontrol Listesi
Sorgu çalıştığı hâlde beklediğinden fazla, az veya tekrarlı satır döndürüyorsa aşağıdaki kontrolleri sırayla uygula:
- Sonuçtaki tek bir satırın ne anlama gelmesi gerektiğini açık bir cümleyle yaz.
JOINişleminden önceki ve sonraki satır sayılarını karşılaştır.DISTINCTkullanılan sorguda hangi sütun kombinasyonunun tekilleştirildiğini kontrol et.COUNT(*)ileCOUNT(DISTINCT sütun)sonuçlarını bilinçli biçimde karşılaştır.GROUP BYsütunlarının,SELECTlistesindeki satır anlamıyla uyumlu olduğundan emin ol.- Satırları toplulaştırmadan önce filtrelemek için
WHERE, oluşan grupları filtrelemek için gerektiğindeHAVINGkullan. - Küçük bir örnek veri kümesi hazırlayarak beklenen çıktıyı elle hesapla.
Üç soruluk mini teşhis senaryosu
Bir sorgunun Ayşe için üç satır döndürdüğünü, senin ise müşteri başına tek satır beklediğini düşün. Önce şu soruları yanıtla: Sonuçtaki bir satır müşteriyi mi, siparişi mi temsil ediyor? SELECT listesinde sipariş numarası gibi satırları farklılaştıran bir sütun var mı? Gerçekten tekrarları mı kaldırmak istiyorsun, yoksa müşteri başına bir hesaplama mı yapacaksın?
Sipariş numarası seçilmişse üç satır hata olmayabilir; sonuç sipariş düzeyindedir. Müşteri başına sayı gerekiyorsa sipariş numarasını SELECT listesinden çıkarıp GROUP BY ve COUNT(*) kullanmalısın. Sorunu yalnızca DISTINCT ekleyerek gizlemeye çalışmak, yanlış satır düzeyini düzeltmez. SQL temel bilgini ayrıca ücretsiz SQL ve algoritmik düşünme testleriyle ölçebilirsin.
Sık Sorulan Sorular
DISTINCT ile GROUP BY aynı sorguda birlikte kullanılabilir mi?
Sözdizimsel olarak kullanılabilir; ancak çoğu temel sorguda ikisine birden ihtiyaç duyulmaz. GROUP BY zaten sonucu belirtilen gruplar düzeyinde üretir. Eklenen DISTINCT sonucu değiştirmiyorsa gereksizdir ve sorgunun asıl amacını belirsizleştirebilir.
COUNT(*) ile COUNT(DISTINCT sütun) arasındaki fark nedir?
COUNT(*) gruptaki satırları sayar. COUNT(DISTINCT sütun) ise belirtilen sütundaki benzersiz ve NULL olmayan değerleri sayar. Örneğin üç siparişte iki farklı kategori varsa sonuçlar sırasıyla 3 ve 2 olur.
HAVING yerine WHERE kullanırsam müşteri başına sipariş sayısını filtreleyebilir miyim?
WHERE, satırları gruplama ve sayma işleminden önce filtreler; bu nedenle doğrudan COUNT(*) sonucuna koşul uygulayamaz. “İkiden fazla siparişi olan müşteriler” gibi grup sonucuna dayalı bir koşul için HAVING COUNT(*) > 2 kullanılmalıdır.
Doğru seçim, komut adlarını ezberlemekten önce sonuçtaki her satırın neyi temsil ettiğini belirlemekle başlar.