SQL DISTINCT: Tekrarsız Değerleri Listeleme ve Tekil Sayım
Beceri rehberi

SQL DISTINCT: Tekrarsız Değerleri Listeleme ve Tekil Sayım

Hazırlayan: Mindset Institute EditörlüğüGüncellendi: 5 dk okuma

DISTINCT, sonuçtaki aynı satırları teke indirir; COUNT(DISTINCT) ise bir sütunda kaç farklı değer olduğunu verir. Hangi sayımın neyi saydığını ve DISTINCT'in nerede tuzak kurduğunu örneklerle öğrenirsiniz.

Bir bakışta

  1. DISTINCT tek bir sütunu değil, seçilen satırın tamamını karşılaştırır. Seçim listesine sütun eklemek, tekil kabul edilen kombinasyonların çoğalmasına yol açar.
  2. COUNT(DISTINCT sütun) farklı ve boş olmayan değerleri sayar. COUNT(*) tüm satırları, COUNT(sütun) ise dolu değerleri sayar; her biri farklı bir sorunun cevabıdır.
  3. DISTINCT mükerrer satırın nedenini çözmez, yalnız gizler. Birleştirme sonrası çoğalan satırlar DISTINCT ile susturulursa hata sonraki raporda yeniden çıkar.
  4. Çok sütunlu tekil sayımın söz dizimi sistemden sisteme değişir. Alt sorguda DISTINCT alıp dışarıda COUNT(*) kullanmak her yerde çalışan güvenli yoldur.

SELECT DISTINCT ne yapar?

SELECT DISTINCT, sorgu sonucundaki aynı satırlardan yalnızca birini bırakır. Kıstas tek bir sütun değil, seçim listesindeki sütunların tamamıdır. Müşteri tablosunda şehirleri tekrarsız görmek istediğinizde şu sorgu yeterlidir:

SELECT DISTINCT sehir FROM musteri;

Seçim listesine bir sütun daha eklediğinizde karşılaştırma ikisi birlikte yapılır:

SELECT DISTINCT sehir, sektor FROM musteri;

Bu sorgu her şehir ve sektör kombinasyonunu bir kez döndürür. İzmir'deki birden fazla perakende müşterisi tek satıra iner, ama İzmir'deki perakende ve bankacılık müşterileri ayrı satırlar olarak kalır. Yani DISTINCT sütun başına değil, satır başına çalışır; bu yüzden "sadece şehre göre tekilleştirsin ama sektörü de göstersin" isteği DISTINCT ile karşılanamaz.

NULL değerler DISTINCT açısından birbirine eşit sayılır. Şehri boş olan çok sayıda müşteri olsa bile sonuçta NULL tek satır olarak görünür. Bu davranış, normal karşılaştırmada NULL = NULL ifadesinin doğru çıkmamasından farklıdır ve rapor yazarken akılda tutulmalıdır.

SQL Server, PostgreSQL ve MySQL'de aynı biçimde çalışan bu temel kullanımın dışında PostgreSQL'e özgü bir biçim vardır: DISTINCT ON. Belirtilen ifadelere göre her grubun ilk satırını tutar ve hangisinin ilk sayılacağı ORDER BY ile belirlenir. Diğer sistemlerde bu söz dizimi yoktur; orada aynı iş pencere fonksiyonlarıyla yapılır.

COUNT(DISTINCT) ile tekil sayım

Sayım yaparken birkaç ayrı soru birbirine karışır. COUNT(*) sonuçtaki tüm satırları sayar, NULL içerenler ve mükerrerler dahil. COUNT(sütun) o sütunda değeri dolu olan satırları sayar. COUNT(DISTINCT sütun) ise o sütundaki farklı ve boş olmayan değerleri sayar. Sipariş tablosundan örnek:

SELECT COUNT(*) AS siparis_adedi, COUNT(musteri_id) AS dolu_musteri_kaydi, COUNT(DISTINCT musteri_id) AS tekil_musteri FROM siparis;

İlk sütun kaç sipariş olduğunu, son sütun ise o siparişleri kaç farklı müşterinin verdiğini söyler. Aynı müşteri defalarca sipariş verdiyse siparişte her seferinde, tekil müşteride yalnızca bir kez sayılır. "Aktif müşteri sayısı", "ürünü alan farklı kişi" ya da "bir ayda giriş yapan tekil kullanıcı" gibi ölçülerin hepsi bu kalıptır.

Gruplayarak kullanmak çok yaygındır:

SELECT ay, COUNT(DISTINCT musteri_id) AS tekil_musteri FROM siparis GROUP BY ay;

Burada her ay için ayrı bir tekil sayım yapılır. Ay toplamlarını toplayıp yıllık tekil müşteri bulmaya çalışmak yanlıştır: bir müşteri birden fazla ayda sipariş verdiyse her ayda ayrıca sayılır. Yıllık sayı için tüm dönemde ayrı bir COUNT(DISTINCT) çalıştırılmalıdır.

Şekil 1

Neyi saymak istediğinize göre sayım ifadesi seçilir

COUNT'un üç biçimi

Sayımın cevaplayacağı soru nedir?
  1. Sonuçta kaç satır var?COUNT(*)NULL içeren ve mükerrer satırlar da sayılır.
  2. Bu sütunu dolu olan kaç satır var?COUNT(sütun)NULL değerler sayıma girmez, tekrarlar sayılır.
  3. Bu sütunda kaç farklı değer var?COUNT(DISTINCT sütun)Her değer bir kez sayılır, NULL dışarıda kalır.
Kaynak: Microsoft COUNT (Transact-SQL) belgesiMindset Institute

Birden çok sütunda tekil kombinasyonu sayma

Bazen "kaç farklı müşteri ve ürün çifti satın alma yaptı" gibi birden çok sütunun birlikte tekil olduğu kombinasyonları saymak gerekir. Söz dizimi burada sistemden sisteme ayrılır: bazı sistemler COUNT(DISTINCT a, b) biçimini kabul eder, bazıları kabul etmez ya da farklı bir ifade ister. Hangi sistemde çalıştığınızı ezberlemek yerine her yerde çalışan kalıbı kullanın: önce DISTINCT ile kombinasyonları çıkarın, sonra dışarıdan sayın.

SELECT COUNT(*) AS tekil_cift FROM ( SELECT DISTINCT musteri_id, urun_id FROM siparis_kalemi ) AS t;

İçteki sorgu her müşteri ve ürün çiftini yalnızca bir kez bırakır, dıştaki sorgu bu çiftleri sayar. Alt sorguya takma ad vermek (burada t) çoğu sistemde zorunludur. Kalıp aynı zamanda okunabilirdir: içteki sorguyu tek başına çalıştırıp sonucu gözle kontrol edebilirsiniz.

Bu yöntem birkaç sütun için de geçerlidir. Seçim listesine sütun ekledikçe tekil kabul edilen kombinasyon sayısı artar, yani sayı hiçbir zaman azalmaz. Sayım beklediğinizden yüksek çıkıyorsa listeye gerekmeyen bir sütun, örneğin işlem zamanı gibi her satırda farklı bir değer girmiş olabilir.

DISTINCT mükerrer satırı gizler, nedenini çözmez

DISTINCT'in en sık yanlış kullanımı, birleştirme sonrası çoğalan satırları susturmaktır. Müşteri tablosunu sipariş tablosuyla birleştirdiğinizde her sipariş için müşteri satırı yinelenir. Sonuç "çok satır geldi" diye sorguya DISTINCT eklenirse ekran düzelir, ama sorgunun mantığı yanlış kalır: gerçekte sormak istediğiniz müşteri mi, sipariş mi?

Önce şu sorulara bakın: birleştirme koşulu eksik mi, bire çok ilişkiyi göz ardı mı ettiniz, tabloda gerçek mükerrer kayıt mı var? Çoğalma ilişkiden geliyorsa çözüm sorguyu yeniden kurmaktır; örneğin yalnızca müşteri bilgisi gerekiyorsa EXISTS ile siparişi olanları seçmek hem daha anlaşılır hem de çoğu zaman daha ucuzdur. Tabloda gerçek mükerrer kayıt varsa bu ayrı bir veri temizliği işidir.

Bir de maliyet konusu vardır. Tekil satırları bulmak için veritabanının sonucu sıralaması ya da özetlemesi gerekir; büyük sonuçlarda bu fark edilir. Aynı işi GROUP BY ile de yapabilirsiniz ve çoğu durumda sonuç aynıdır. Fark, GROUP BY'ın özet fonksiyonlarıyla birlikte kullanılabilmesidir. Yalnızca tekilleştirme amacıyla DISTINCT daha kısa ve niyeti açık olan yazımdır.

Son bir ayrıntı: SELECT DISTINCT kullandığınızda ORDER BY'daki ifadelerin seçim listesinde bulunması gerekir. Listede olmayan bir sütuna göre sıralamak istediğinizde sistem hata verir, çünkü tekilleştirilmiş satırın o sütundaki değeri belirsizdir.

Sık hatalar ve kontrol listesi

Tekil sorgularda aynı birkaç hata tekrar eder.

  • Her sütuna DISTINCT yazmaya çalışmak: DISTINCT bir fonksiyon değil, seçim listesinin tamamına uygulanan bir niteleyicidir; SELECT DISTINCT a, DISTINCT b geçersizdir.
  • COUNT(DISTINCT) sonucunu parçalayıp toplamak: aylık tekil sayıların toplamı yıllık tekil sayıya eşit değildir.
  • NULL'ın sayıma girdiğini varsaymak: COUNT(DISTINCT sütun) NULL'ı saymaz, boş değerleri ayrıca saymak istiyorsanız COUNT(*) ile farkına bakın.
  • Büyük/küçük harf ve boşluk farklarını unutmak: "Ankara" ile "ankara " veritabanı için ayrı değerler olabilir; ayarlara göre karşılaştırma harfe duyarlı olabilir. Önce metni temizleyip sonra sayın.
  • Sonucu doğrulamadan raporlamak: tekil sayıyı küçük bir örnek veri üzerinde elle kontrol edin.

Sorgunuzu teslim etmeden önce şu sırayı izleyin: önce DISTINCT olmadan sorguyu çalıştırıp satırların neden tekrar ettiğini görün, sonra tekilleştirmenin gerçekten istediğiniz şey olup olmadığına karar verin, en sonda sayım ifadesini ekleyin. Sorgu yeniden kullanılacaksa takma adlara anlamlı isimler verin; tekil_musteri, toplam_satir gibi isimler raporu okuyanın hangi sayımın yapıldığını bilmesini sağlar.

Tekrarlı kayıtları bulup silmek ise farklı bir iştir; orada hangi kaydın kalacağına karar vermek gerekir.

Bu beceriyi Mindset programında nerede çalışırsınız?

Mindset'in SQL ile Programlama Eğitimi, Sorgular ve Toplama ve Gruplama modüllerinde bu konuya doğrudan temas eder. Raporlama ya da veri analizi yapan bir ekipte çalışıyorsanız, kendi tablolarınız üzerinde tekil müşteri ve tekil ürün sayımlarını denemek en kısa öğrenme yoludur.

Programa gelmeden önce yapabileceğiniz bir hazırlık, kendi işinizden birkaç ölçü seçip bunların COUNT(*) ve COUNT(DISTINCT) ile nasıl farklı sonuç verdiğini bir örnek tabloda görmektir.

İlgili Mindset programı

SQL ile Programlama Eğitimi

Sık sorulanlar

Sık sorulan sorular

DISTINCT ile GROUP BY aynı sonucu verir mi?

Yalnızca tekilleştirme amacıyla kullanıldıklarında çoğu zaman aynı satırları döndürürler. Fark, GROUP BY'ın toplam, ortalama gibi özet fonksiyonlarıyla birlikte çalışması ve her grup için hesap yapabilmesidir. Yalnızca farklı değerleri listelemek istiyorsanız DISTINCT niyeti daha açık gösterir.

DISTINCT NULL değerlerini siler mi?

Hayır. DISTINCT, NULL değerleri birbirine eşit sayar ve sonuçta NULL için tek bir satır bırakır. Buna karşılık COUNT(DISTINCT sütun) NULL değerleri saymaz. NULL'ı da görmek istiyorsanız sorguyu DISTINCT ile listeleyin ya da boş satırları ayrıca sayın.

Birden çok sütunun birlikte tekil olduğu satırları nasıl sayarım?

Çok sütunlu COUNT(DISTINCT) söz dizimi sistemlere göre değiştiği için alt sorgu kullanın: içeride SELECT DISTINCT ile sütunları çıkarın, dışarıda COUNT(*) alın. Bu kalıp SQL Server, PostgreSQL ve MySQL'de aynı çalışır.

DISTINCT sorguyu yavaşlatır mı?

Veritabanı tekil satırları bulmak için sıralama ya da özetleme yapmak zorundadır, bu da büyük sonuçlarda ek iş demektir. Küçük tablolarda fark hissedilmez. Yavaşlık görürseniz önce gereksiz sütunları seçim listesinden çıkarın ve sorgu planına bakın.

Tablodaki mükerrer kayıtları DISTINCT ile silebilir miyim?

Hayır, DISTINCT yalnızca sorgu sonucunu etkiler, tablodaki veriyi değiştirmez. Mükerrer kayıtları kalıcı olarak temizlemek için hangi kopyanın kalacağını belirleyen ayrı bir silme sorgusu yazmak gerekir.

SQL DISTINCT ve COUNT(DISTINCT) ile Tekil Kayıt