Aggregate Fonksiyon Aslında Ne Yapar?
Şu ana kadar gördüğünüz SQL fonksiyonlarının çoğu satır satır çalışıyordu: UPPER(name) her satırda bir kez çalışır, ROUND(price, 2) de öyle. Ama sqlite aggregate fonksiyonlar farklı bir mantıkla çalışır. Bütün bir satır kümesine bakar ve bunu tek bir değere indirger.
Üzerinde denemeler yapabileceğin küçük bir tablo hazırlayalım:
Beş satır girer, bir satır çıkar. Aggregate fonksiyonlarının özü tam olarak bu: birden fazla satırı tek bir özete sıkıştırırlar. GROUP BY kullanmazsan, bu özet sonuçtaki tüm satırları kapsar.
COUNT: Satır mı, Değer mi?
COUNT fonksiyonunun üç farklı kullanımı var ve aradaki fark gerçekten önemli:
COUNT(*)satırları sayar. NULL'lar da dahildir. Her zaman bir sayı döner.COUNT(column)o sütundaki NULL olmayan değerleri sayar.COUNT(DISTINCT column)ise NULL olmayan benzersiz değerleri sayar.
Beş satırımız var: üçünde amount dolu, üç farklı müşteri mevcut. COUNT(amount) sonucunun COUNT(*)'tan neden daha küçük çıktığını merak ediyorsanız sebebi tam olarak bu — NULL'lar sayıma dahil edilmez.
SUM, AVG, MIN, MAX
Aritmetik aggregate fonksiyonlar beklediğiniz gibi çalışır; ama hepsinin sessiz sedasız uyduğu tek bir kural var: NULL değerleri atlarlar:
AVG'nin sonucu (10 + 20 + 30) / 3 = 20.0 olur, 60 / 4 = 15.0 değil. Yani paydadaki sayı, NULL olmayan değerlerin adedidir. Eğer istediğiniz bu değilse — eksik veriyi sıfır gibi saymak istiyorsanız — bunu açıkça belirtmeniz gerekir:
MIN ve MAX fonksiyonları sadece sayılarla değil, metin ve tarih değerleriyle de çalışır. Metinleri sözlük sırasına göre, ISO formatındaki standart tarihleri ise dize olarak karşılaştırır.
SUM ile TOTAL arasındaki fark
SQLite'ta SUM'a benzer ikinci bir toplama fonksiyonu daha var: TOTAL. Bu fonksiyon, SUM'ın can sıkıcı iki davranışını düzeltir:
- Hiç satır yokken
SUMNULLdöner.TOTALise0.0verir. - Tüm değerler
NULLolduğundaSUMyineNULLdöner;TOTALyine0.0verir. TOTALher zaman ondalıklı bir sayı döndürür, dolayısıyla integer taşması yaşanmaz.
Madalyonun öbür yüzü: TOTAL standart dışıdır ve sonucun her zaman REAL olması, integer beklediğiniz yerlerde sizi şaşırtabilir. "Satır yoksa sıfır olsun" davranışı uygulamanız için doğruysa TOTAL kullanın; SQL standardına uygun davranış istiyorsanız SUM'da kalın.
Aggregate İçinde DISTINCT Kullanımı
DISTINCT yalnızca COUNT ile değil, herhangi bir aggregate fonksiyonun içinde kullanılabilir. Tekrarlanan değerleri toplama işlemi çalışmadan önce ayıklar:
SUM(amount) her satırdaki tutarı toplar. SUM(DISTINCT amount) ise her benzersiz tutarı yalnızca bir kez toplar — "benzersiz fatura tutarlarının toplamı" gibi durumlarda işe yarar ama çoğu zaman istediğiniz şey bu değildir. Asıl yaygın kullanım COUNT(DISTINCT customer).
FILTER: Aggregate'i Belirli Satırlara Uygulamak
Satırların yalnızca bir kısmını toplamak istediğinizde ilk akla gelen WHERE olur. Ama WHERE sorgunun tamamını filtreler — yani aynı sorguda hem "ödenen siparişleri say" hem de "iadeleri say" diyemezsiniz. İşte tam burada FILTER devreye giriyor:
Her FILTER (WHERE ...) ifadesi yalnızca bağlı olduğu aggregate'i etkiler. Tablo bir kez taranır, ama birden fazla dilim aynı sorguda özetlenir. FILTER dilde yokken aynı şeyi SUM(CASE WHEN status = 'paid' THEN amount END) yazarak yapardık — mantık aynı, ama daha çok tuş darbesi.
GROUP_CONCAT: String'leri birleştirmek
GROUP_CONCAT, diğerlerinden biraz farklı. Sayı döndürmek yerine değerleri tek bir string'e birleştirir:
Varsayılan ayraç virgüldür. Farklı bir şey kullanmak istiyorsanız ikinci bir argüman verebilirsiniz. Sıralama, çağrıyı GROUP_CONCAT(tag ORDER BY tag) şeklinde yazmadıkça garanti edilmez — sonuç bir arayüzde gösterilecekse ve sıralamanın tutarlı olmasını istiyorsanız bu yaklaşım çok işe yarar.
GROUP BY Olmadan Aggregate Kullanımı
Buraya kadar GROUP BY olmadan aggregate kullandığımız her örnek tek bir satır döndürdü. Kural net: GROUP BY içermeyen ve aggregate fonksiyon barındıran bir SELECT, (varsa WHERE uygulandıktan sonra) tablonun tamamını tek satırda özetler.
Aggregate fonksiyonları rahatlıkla bir arada kullanabilirsiniz:
Aggregate fonksiyonları, gruplanmamış (non-aggregated) sütunlarla birlikte kullanıp anlamlı bir sonuç beklemek ise yapamayacağınız bir şeydir:
-- SQLite tarafından izin verilir, ancak `customer` değeri rastgeledir.
SELECT customer, SUM(amount) FROM orders;
SQLite burada hata vermez (başka veritabanları verir), ama toplamla birlikte gösterilecek müşteri adını rastgele seçer. Müşteri başına toplam istiyorsanız GROUP BY kullanmanız gerekir — bir sonraki sayfanın konusu da bu zaten.
Sırada: GROUP BY ve HAVING
Tüm tablo üzerinden hesaplanan aggregate fonksiyonlar "toplamda ne kadar" sorusuna cevap verir. Asıl ilginç sorular ise grup bazında alınan toplamlardan çıkar: müşteri başına, ay başına, durum başına. GROUP BY satırları kovalara ayırarak aggregate işleminden önce gruplamanızı sağlar; HAVING ise gruplanmış sonuç üzerinde filtreleme yapmanıza imkân tanır. Sırada bu var.
Sıkça Sorulan Sorular
SQLite'ta aggregate fonksiyonlar nedir?
Aggregate fonksiyonlar, birçok satırı alıp tek bir özet değer döndürür. SQLite'ın yerleşik aggregate fonksiyonları şunlardır: COUNT, SUM, AVG, MIN, MAX, TOTAL ve GROUP_CONCAT. GROUP BY kullanmazsanız, tüm sonuç kümesini tek bir satıra indirgerler.
SQLite'ta SUM ile TOTAL arasındaki fark nedir?
İkisi de toplama yapar ama farkları var: SUM tüm girdiler NULL ise NULL döner ve mümkün olduğunda integer aritmetiği kullanır (yani taşma riski vardır). TOTAL ise her zaman ondalıklı (floating-point) bir sayı döner ve hiç satır yoksa 0.0 üretir. Sonucun garanti şekilde sayısal olmasını istiyorsanız TOTAL, SQL standardına uygun davranış istiyorsanız SUM kullanın.
SQLite'ta benzersiz (distinct) değerler nasıl sayılır?
DISTINCT anahtar kelimesini fonksiyonun içine koyun: COUNT(DISTINCT customer_id). Bu, NULL olmayan benzersiz değerlerin sayısını verir. Düz COUNT(column) ise NULL olmayan değerleri tekrarlarıyla birlikte sayar; COUNT(*) ise NULL'lar dahil tüm satırları sayar.
SQLite aggregate fonksiyonları NULL değerleri yok sayar mı?
Evet — COUNT(*) dışındaki tüm aggregate fonksiyonlar NULL girdileri atlar. Mesela AVG, toplam satır sayısına değil, NULL olmayan değerlerin sayısına böler. İstisna olan COUNT(*), değerleri değil satırları saydığı için NULL'lar da dahil edilir.