Sessiz hatalar en tehlikelisidir
Hata veren sorgu kolay düzeltilir. Asıl tehlike, çalışan ama yanlış sonuç döndüren sorgulardır. Bu derste her alıştırma hatalı bir sorguyla başlar; hatayı bul ve düzelt.
| Tuzak | Belirti | Çözüm |
|---|---|---|
= NULL | Hiç satır gelmez | IS NULL |
NOT IN + NULL | Hiç satır gelmez | NOT EXISTS veya alt sorguda IS NOT NULL |
| LEFT JOIN + WHERE sağ tablo | LEFT JOIN, INNER'a dönüşür | Koşulu ON'a taşı |
LEFT JOIN + COUNT(*) | Eşi olmayanlar 1 sayılır | COUNT(sağ_tablo.id) |
| Tam sayı bölmesi | Oranlar 0 çıkar | 100.0 * pay / payda |
| JOIN sonrası toplam | Toplamlar şişer (fan-out) | Önce topla, sonra birleştir |
| AND/OR önceliği | Fazla satır gelir | Parantez |
Derinleş: hata ayıklama listesi
Bir sonuç “yanlış gibi” görünüyorsa sırayla şunlara bak:
- Her JOIN'den sonra satır sayısı değişti mi?
- LEFT JOIN'in sağ tablosuna WHERE ile koşul yazdın mı?
- Oranlarda pay ve payda aynı grain düzeyinde mi; tam sayı bölmesi var mı?
- NULL içeren sütunlarda
=,<>ya da NOT IN kullandın mı? - Tarih aralığının üst sınırı saatli kayıtları dışarıda bırakıyor mu?
- Eşitlikte sıralama belirsiz mi (ORDER BY'a ikinci anahtar eklendi mi)?
Bu listenin tamamını uygulamalı görmek için Sorgu hata ayıklama dersine geç.
Derinleş: tarih aralığı, NOT IN ve AND/OR tuzakları
Aşağıdaki üç hata, sorgu hiç hata vermediği için en uzun süre fark edilmeyenlerdir. Üçü de Lezzet Kurye verisinde gerçek sayı farkı yaratıyor.
1. BETWEEN ve saatli tarih
placed_at saat içerir. BETWEEN '2024-12-01' AND '2024-12-31' üst sınırı 2024-12-31 00:00:00 olarak yorumlar ve 31 Aralık'ın neredeyse tamamını dışarıda bırakır:
SELECT (SELECT COUNT(*) FROM lk_orders WHERE placed_at BETWEEN '2024-12-01' AND '2024-12-31') AS between_ile, (SELECT COUNT(*) FROM lk_orders WHERE placed_at >= '2024-12-01' AND placed_at < '2025-01-01') AS aralik_ile;
Fark 74 sipariş: tam olarak 31 Aralık'ın siparişleri. Kural: tarih aralıklarını her zaman yarı açık yaz (>= başlangıç AND < bitişten sonraki gün).
2. NOT IN ve alt sorgudaki NULL
İptal edilen siparişlerin bir kısmında kurye atanmamış (courier_id NULL). “Hiç iptal siparişi olmayan kuryeler” sorusu NOT IN ile sorulursa:
SELECT
(SELECT COUNT(*) FROM lk_couriers
WHERE courier_id NOT IN (SELECT courier_id FROM lk_orders WHERE status = 'iptal')) AS not_in_ile,
(SELECT COUNT(*) FROM lk_couriers c
WHERE NOT EXISTS (SELECT 1 FROM lk_orders o
WHERE o.courier_id = c.courier_id AND o.status = 'iptal')) AS not_exists_ile;
NOT IN 0 döndürür, doğru cevap 6'dır. Listede bir NULL varsa x NOT IN (…, NULL) hiçbir zaman TRUE olamaz (sonuç UNKNOWN), bu yüzden hiçbir satır geçmez.
3. AND, OR'dan önce gelir
WHERE status = 'iptal' AND payment = 'nakit' OR payment = 'cüzdan', motor tarafından (status = 'iptal' AND payment = 'nakit') OR payment = 'cüzdan' olarak okunur ve durumu ne olursa olsun tüm cüzdan siparişlerini getirir: 130 yerine 1.487 satır. OR içeren her koşulu parantezle.
4. AVG ve NULL
Lezzet Kurye'de 60 kuryenin 59'unun puanı var. AVG(rating) NULL'u atlayıp 4,22 verir; AVG(COALESCE(rating, 0)) ise puansız kuryeyi 0 sayıp ortalamayı 4,14'e düşürür. Hangisinin doğru olduğu sorunun tanımına bağlıdır, ama sessizce değişmemelidir.
| Tuzak | Kontrol sorusu |
|---|---|
| BETWEEN + saat | Sütun saat içeriyor mu? Son günün kayıtları geliyor mu? |
| NOT IN + NULL | Alt sorgunun sütununda NULL olabilir mi? |
| AND/OR | OR'un iki yanı parantez içinde mi? |
AVG + NULL | NULL'lar hesaba katılmalı mı? (AVG onları atlar) |