Ders 10 / 18
Toplama İşlevleri
Satır kümesini tek değere indirgeyen sayım, toplam, ortalama ve uç değer işlevleri; boş değerlerin atlanması, yıldızlı sayım ile sütunlu sayımın farkı ve boş kümenin sonucu.
İçindekiler
Önceki üç ders satır düzeyinde kaldı: her sonuç satırı, kaynak satırların bir bileşimine karşılık geliyordu. Sorgu ne kadar tablo birleştirirse birleştirsin, ürettiği şey yine satırlardı.
“Kaç kitap var”, “ortalama ödünç süresi ne”, “en eski basım hangi yıl” gibi sorular başka bir şey ister: bir satır kümesinin tek bir değerle özetlenmesini. Bunu yapan işlevlere toplama işlevi (aggregate function) denir. Skaler işlevlerden farkları, girdilerinin tek satır değil bir satır kümesi olmasıdır.
Aşağıdaki blok şemayı ve örnek veriyi kurar; dersin bütün sorguları bu blokta oluşturulan
kutuphane.db dosyası üzerinde çalışır.
rm -f kutuphane.db sqlite3 kutuphane.db <<'SQL' CREATE TABLE sube (sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL); CREATE TABLE kitap (kitap_id INTEGER PRIMARY KEY, baslik TEXT NOT NULL, yazar TEXT NOT NULL, basim_yili INTEGER, sube_id INTEGER REFERENCES sube(sube_id)); CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL, eposta TEXT, kayit_tarihi TEXT NOT NULL); CREATE TABLE odunc (odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL REFERENCES kitap(kitap_id), uye_id INTEGER NOT NULL REFERENCES uye(uye_id), alis_tarihi TEXT NOT NULL, iade_tarihi TEXT); INSERT INTO sube VALUES (1,'Merkez','Ankara'),(2,'Bahçelievler','Ankara'), (3,'Kadıköy','İstanbul'),(4,'Konak','İzmir'); INSERT INTO kitap VALUES (1,'Körlük','José Saramago',1995,1),(2,'Tutunamayanlar','Oğuz Atay',1972,1), (3,'Kum Kitabı','Jorge Luis Borges',1975,2),(4,'Yaban','Yakup Kadri',1932,2), (5,'Sessiz Ev','Orhan Pamuk',1983,3),(6,'Anayurt Oteli','Yusuf Atılgan',NULL,3), (7,'Tehlikeli Oyunlar','Oğuz Atay',1973,NULL); INSERT INTO uye VALUES (1,'Ayşe','Demir','[email protected]','2023-02-14'), (2,'Mehmet','Kaya','[email protected]','2023-05-30'),(3,'Zeynep','Arslan',NULL,'2024-01-09'), (4,'Emre','Yıldız','[email protected]','2024-03-22'),(5,'Selin','Aydın',NULL,'2024-11-05'), (6,'Burak','Şahin','[email protected]','2025-01-18'); INSERT INTO odunc VALUES (1,1,1,'2025-01-10','2025-01-24'),(2,2,1,'2025-02-02','2025-02-20'), (3,1,2,'2025-02-11',NULL),(4,3,3,'2025-03-01','2025-03-15'),(5,4,3,'2025-03-18','2025-04-02'), (6,1,4,'2025-04-05','2025-04-19'),(7,5,4,'2025-04-21',NULL),(8,2,5,'2025-05-02','2025-05-30'), (9,7,1,'2025-05-14','2025-05-28'),(10,3,5,'2025-06-03',NULL),(11,6,2,'2025-06-11','2025-06-25'), (12,4,4,'2025-06-20','2025-07-04'); SQL
Sayımın Üç Biçimi
Sayım işlevinin üç yazımı vardır ve üçü farklı şeyler sayar.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT COUNT(*) AS satir, COUNT(basim_yili) AS yili_bilinen, COUNT(DISTINCT yazar) AS ayri_yazar FROM kitap; SQL
satir yili_bilinen ayri_yazar ----- ------------ ---------- 7 6 6
COUNT(*) satırları sayar; sütun değerlerine hiç bakmaz, yedi satır yedidir.
COUNT(basim_yili) o sütundaki boş olmayan değerleri sayar; basım yılı bilinmeyen
kitap sayıma girmedi, sonuç altı oldu. COUNT(DISTINCT yazar) ise boş olmayan ayrı
değerleri sayar; yedi kitabın altı yazarı var.
Bu ayrım toplama işlevlerinin genel kuralının ilk örneğidir: toplama işlevleri boş
değerleri atlar. Tek istisna COUNT(*), çünkü bir sütuna değil satırın kendisine bakar.
Aynı ayrım ödünç tablosunda doğrudan bir soruya karşılık gelir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT COUNT(*) AS kayit, COUNT(iade_tarihi) AS iade_edilen FROM odunc; SQL
kayit iade_edilen ----- ----------- 12 9
On iki ödünç kaydının dokuzu iade edilmiş. İkinci sütun, iade tarihi boş olan üç kaydı saymadı — hiçbir koşul yazılmadan, yalnız boş değer kuralının sonucu olarak.
Toplam, Ortalama ve Uç Değerler
Dört işlev daha aynı aileyi tamamlar.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT MIN(basim_yili) AS en_eski, MAX(basim_yili) AS en_yeni, SUM(basim_yili) AS toplam, AVG(basim_yili) AS ortalama FROM kitap; SQL
en_eski en_yeni toplam ortalama ------- ------- ------ ---------------- 1932 1995 11830 1971.66666666667
Dördü de boş değeri atladı. Toplam altı sayının toplamı, ortalama da altıya bölünmüş hali. Ortalamanın kaça bölündüğü, boş değerlerin en sık gözden kaçan sonucudur.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT AVG(basim_yili) AS ortalama, SUM(basim_yili) * 1.0 / COUNT(*) AS satira_bolunen, SUM(basim_yili) * 1.0 / COUNT(basim_yili) AS dolu_degere_bolunen FROM kitap; SQL
ortalama satira_bolunen dolu_degere_bolunen ---------------- -------------- ------------------- 1971.66666666667 1690.0 1971.66666666667
Ortada duran sayı yanlış. Toplam altı değerden geliyor, COUNT(*) ise yedi satır sayıyor;
bölme, olmayan bir kitabı sıfır basım yılıyla hesaba katmış gibi davranıyor. Ortalama
işlevi ile üçüncü sütun aynı sonucu veriyor, çünkü ikisi de yalnız dolu değerleri sayıyor.
Karar, boş değerin ne anlama geldiğine bağlıdır. “Bilinmiyor” ise ortalamanın dışında tutulması doğrudur. “Sıfır” anlamına geliyorsa şema yanlıştır: sıfır bir değerdir ve sütuna sıfır yazılmalıdır. İki durumu birbirine karıştırmak, veriden çıkan sayıları sessizce bozar.
Uç değer işlevleri metin sütunlarında da çalışır ve sonuç harmanlamaya bağlıdır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT MIN(baslik) AS ilk, MAX(baslik) AS son FROM kitap; SQL
ilk son ------------- ----- Anayurt Oteli Yaban
Dördüncü derste görülen kural burada da geçerli: hangi metnin “en küçük” sayılacağını karşılaştırma düzeni belirler ve öntanımlı düzen motora göre değişir.
Boş Kümenin Sonucu
Toplama işlevleri hiçbir satır bulamadığında ne döndürür? Sayım ile toplam bu soruya farklı yanıt verir.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT COUNT(*) AS satir, SUM(basim_yili) AS toplam, COALESCE(SUM(basim_yili), 0) AS guvenli FROM kitap WHERE yazar = 'Bilinmeyen Yazar'; SQL
satir toplam guvenli ----- ------ ------- 0 0
Sorgu hiçbir satır bulmadı. Sayım 0 döndürdü — sıfır satır saymak tanımlı bir işlem.
Toplam ise boş döndürdü, 0 değil: hiçbir sayı yoksa toplam da tanımsızdır. Bu ayrım
kuramsal olarak tutarlıdır ama pratikte hataya yol açar, çünkü toplamı bir hesaba sokan
kod genellikle sayı bekler.
Ayrıca dikkat edilecek nokta şudur: toplama işlevi içeren ve gruplaması olmayan bir sorgu, kaynak satır bulunmasa bile her zaman bir satır döndürür. Yukarıdaki çıktı boş değil; içi boş bir satır. Gruplama eklendiğinde bu davranış değişir ve sonraki dersin konusu olur.
Korunma yolu, toplamı kullanan yerde boş değeri bir yer tutucuya çevirmektir — üçüncü sütundaki yazım bunu yapıyor.
Toplama ile Sütunu Karıştırmak
Toplama işlevi bütün satır kümesini tek satıra indirger. Aynı sorguda gruplanmamış bir sütun da istenirse mantıksal bir çelişki doğar: hangi satırın değeri gösterilecektir?
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT baslik, MAX(basim_yili) AS en_yeni FROM kitap; SQL
baslik en_yeni ------ ------- Körlük 1995
Sorgu çalıştı ve tutarlı bir yanıt verdi: en yeni basımın başlığı gerçekten Körlük.
Ancak bu, motora göre değişen bir davranıştır. Standart, gruplanmamış bir sütunun
toplama işleviyle birlikte seçilmesine izin vermez; bazı motorlar hata verir, bazıları
rastgele bir satırın değerini döndürür, bu motor ise uç değer işlevleriyle birlikte
kullanıldığında eşleşen satırı seçer.
Kural olarak bu yazımdan kaçınılmalıdır. Uç değeri veren satırın tamamı isteniyorsa doğru araç sıralama ile sınırlamadır ya da İleri SQL kursunda ele alınan pencere işlevleridir.
Birleştirme ile Birlikte Toplama
Toplama işlevleri birleştirilmiş bir sonuç üzerinde de çalışır. Ödünç süresi, iki tarih sütununun farkı olduğu için hesaplanmış bir ifade üzerinden toplanır.
sqlite3 kutuphane.db <<'SQL' .headers on .mode column SELECT COUNT(*) AS kayit, COUNT(iade_tarihi) AS iade_edilen, ROUND(AVG(julianday(iade_tarihi) - julianday(alis_tarihi)), 2) AS ortalama_gun FROM odunc; SQL
kayit iade_edilen ortalama_gun ----- ----------- ------------ 12 9 16.11
Üç sütun aynı tabloyu farklı büyüklüklerle özetliyor: on iki kayıt var, dokuzu iade edilmiş, iade edilenlerin ortalama süresi on altı günün biraz üzerinde. Ortalamanın paydası yine dokuz; iade edilmemiş kayıtlar için fark hesaplanamadığı için boş değer üretildi ve atlandı.
Birleştirmenin satır çoğaltma etkisi burada bir tuzağa dönüşebilir. Bir kitabı ödünç
kayıtlarıyla birleştirip kitap sayarsa, birden çok kez ödünç alınmış kitaplar birden çok
kez sayılır. Böyle bir sorguda COUNT(DISTINCT kitap_id) yazımı doğru sonucu verir.
Özet
- Toplama işlevleri bir satır kümesini tek değere indirger ve gruplamasız yazıldıklarında sonuç her zaman tek satırdır.
COUNT(*)satırları sayar,COUNT(sütun)o sütundaki boş olmayan değerleri sayar, ayrı değer sayımı ise yinelenenleri bir kez sayar.- Toplama işlevleri boş değerleri atlar; ortalamanın paydası satır sayısı değil dolu değer sayısıdır.
- Boş küme üzerinde sayım sıfır, toplam ise boş değer döndürür.
- Gruplanmamış bir sütunu toplama işleviyle birlikte seçmek standart değildir ve davranışı motora göre değişir.
- Birleştirme satırları çoğalttığında sayımlar şişer; ayrı değer sayımı bunu düzeltir.
Sonraki Adım
Buraya kadarki toplamalar bütün tabloyu tek bir sonuca indirgedi. Oysa asıl işe yarayan
soru genellikle “toplamda kaç” değil, “her şube için kaç”, “her üye için kaç” biçimindedir.
Sonraki ders satırları kümelere ayırıp her küme için ayrı bir özet üreten gruplamayı kurar
ve grupları süzen yan tümcenin WHERE yan tümcesinden neden ayrı olduğunu aynı sorguda
ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.