Ana içeriğe geç
Kesit SQL
Orta · Kanat Havayolları

Alt sorgu ve EXISTS: hiç uçmayan üyeler, ortalamanın üstündeki rotalar

Tek değer döndüren alt sorgu, IN, NOT EXISTS, HAVING içinde alt sorgu ve ilişkili alt sorgu.

Uygulamada aç, 8 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ç.

Sorunun içinde başka bir soru

“Ortalamanın üstünde ödeme yapan rezervasyonlar” derken önce ortalamayı bilmek gerekir. Alt sorgu bu ara sonucu üretir:

SELECT COUNT(*) AS adet
FROM hv_bookings
WHERE price > (SELECT AVG(price) FROM hv_bookings);

Var mı, yok mu? EXISTS

SELECT COUNT(*) AS hic_rezervasyonu_yok
FROM hv_passengers p
WHERE NOT EXISTS (SELECT 1 FROM hv_bookings b WHERE b.passenger_id = p.passenger_id);

Grupları genel ortalamayla karşılaştırmak

SELECT f.route_id, ROUND(AVG(ROUND((julianday(f.actual_dep) - julianday(f.sched_dep)) * 1440)), 1) AS ort_gecikme
FROM hv_flights f
WHERE f.actual_dep IS NOT NULL
GROUP BY f.route_id
HAVING AVG(ROUND((julianday(f.actual_dep) - julianday(f.sched_dep)) * 1440)) > (SELECT AVG(ROUND((julianday(f.actual_dep) - julianday(f.sched_dep)) * 1440)) FROM hv_flights f WHERE f.actual_dep IS NOT NULL)
ORDER BY ort_gecikme DESC
LIMIT 5;
Ne zaman JOIN, ne zaman EXISTS?Diğer tablodan sütun getirmen gerekiyorsa JOIN; yalnızca “karşılığı var mı” sorusu soruluyorsa EXISTS. EXISTS satır çoğaltmaz, ilk eşleşmede durur.

Derinleş: NOT IN ve NULL tuzağı, skaler alt sorgunun yeri

NOT IN ile NOT EXISTS çoğu zaman aynı sonucu verir. Arada tek ama tehlikeli bir fark vardır: alt sorgu bir NULL döndürürse NOT IN hiçbir satır döndürmez.

Sebep üç değerli mantıktır. x NOT IN (a, b, NULL) ifadesi x <> a AND x <> b AND x <> NULL demektir. x <> NULL her zaman UNKNOWN olduğu için bütün ifade hiçbir zaman TRUE olamaz. Aşağıda 26 Aralık 2024'te hiç inişi olmayan uçakları iki yoldan arıyoruz. Alt sorgudaki CASE, inmemiş (iptal) uçuşlar için NULL üretir, tıpkı boş bir sütun gibi:

SELECT 'NOT EXISTS' AS yontem, COUNT(*) AS ucak
FROM hv_aircraft a
WHERE NOT EXISTS (SELECT 1 FROM hv_flights f
                  WHERE f.tail_no = a.tail_no AND f.status = 'landed'
                    AND f.sched_dep >= '2024-12-26' AND f.sched_dep < '2024-12-27')
UNION ALL
SELECT 'NOT IN', COUNT(*)
FROM hv_aircraft a
WHERE a.tail_no NOT IN (SELECT CASE WHEN f.status = 'landed' THEN f.tail_no END
                        FROM hv_flights f
                        WHERE f.sched_dep >= '2024-12-26' AND f.sched_dep < '2024-12-27');

NOT EXISTS 5 uçak bulur. NOT IN ise 0 döndürür, çünkü o gün 3 iptal var ve alt sorgu üç NULL üretir. Sorgu hata vermez, yalnızca sessizce yanlış sonuç verir. Gerçek tablolarda boş bırakılabilen her sütun (email, seat, manager_id …) bu riski taşır.

DurumTercih
“Karşılığı olmayanlar”NOT EXISTS (NULL'a dayanıklı)
NOT IN kullanmak zorundaysanAlt sorguya WHERE sütun IS NOT NULL ekle
“Karşılığı olanlar”IN ya da EXISTS; NULL burada sorun çıkarmaz
Satır başına genel bir değerle kıyasSkaler alt sorgu (SELECT AVG(...)) ya da CTE

Skaler alt sorgu nereye yazılır?

Tek değer döndüren bir alt sorgu SELECT, WHERE ve HAVING içinde kullanılabilir. “Rotanın ortalama ücreti, genel ortalamanın kaç katı?” sorusunda alt sorgu hem SELECT'te (oran) hem HAVING'de (filtre) görünür. Okunabilirlik ya da performans sorun olursa genel ortalamayı bir CTE'de bir kez hesaplayıp CROSS JOIN ile bağlamak aynı işi yapar. Çoğu veritabanı ilişkisiz skaler alt sorguyu zaten bir kez hesaplar.

İlişkili mi, ilişkisiz mi?Alt sorgu dış sorgunun bir sütununa başvuruyorsa (b2.passenger_id = b.passenger_id) ilişkilidir ve kavramsal olarak her dış satır için yeniden çalışır. Büyük tablolarda bunu bir JOIN ya da pencere fonksiyonuyla yeniden yazmak çoğu zaman daha hızlıdır.
Alıştırmalara geç (8)