Ana içeriğe geç
Kesit SQL
Orta · Küme ve Alt Sorgular

Sık yapılan SQL hataları: düzelt ve öğren

Hatalı sorguları bulup düzelterek en yaygın tuzakları pekiştir.

Uygulamada aç, 10 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

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.

TuzakBelirtiÇözüm
= NULLHiç satır gelmezIS NULL
NOT IN + NULLHiç satır gelmezNOT EXISTS veya alt sorguda IS NOT NULL
LEFT JOIN + WHERE sağ tabloLEFT JOIN, INNER'a dönüşürKoşulu ON'a taşı
LEFT JOIN + COUNT(*)Eşi olmayanlar 1 sayılırCOUNT(sağ_tablo.id)
Tam sayı bölmesiOranlar 0 çıkar100.0 * pay / payda
JOIN sonrası toplamToplamlar şişer (fan-out)Önce topla, sonra birleştir
AND/OR önceliğiFazla satır gelirParantez

Derinleş: hata ayıklama listesi

Bir sonuç “yanlış gibi” görünüyorsa sırayla şunlara bak:

  1. Her JOIN'den sonra satır sayısı değişti mi?
  2. LEFT JOIN'in sağ tablosuna WHERE ile koşul yazdın mı?
  3. Oranlarda pay ve payda aynı grain düzeyinde mi; tam sayı bölmesi var mı?
  4. NULL içeren sütunlarda =, <> ya da NOT IN kullandın mı?
  5. Tarih aralığının üst sınırı saatli kayıtları dışarıda bırakıyor mu?
  6. 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.

TuzakKontrol sorusu
BETWEEN + saatSütun saat içeriyor mu? Son günün kayıtları geliyor mu?
NOT IN + NULLAlt sorgunun sütununda NULL olabilir mi?
AND/OROR'un iki yanı parantez içinde mi?
AVG + NULLNULL'lar hesaba katılmalı mı? (AVG onları atlar)
Alıştırmalara geç (10)