LEFT JOIN ve RIGHT JOIN
Giriş — Eşleşmeyenler de Önemli
INNER JOIN sadece eşleşen satırları döndürür. Ama bazen eşleşmeyen satırları da görmek istersin: "Hiç sipariş vermemiş müşteriler", "Hiç satılmamış ürünler", "Çalışanı olmayan departmanlar"...
LEFT JOIN ve RIGHT JOIN bu ihtiyacı karşılar: bir tarafın tüm satırlarını döndürür, diğer taraftan eşleşme yoksa NULL ile doldurur.
🎯 Analoji: Sınıf yoklama listesi (sol tablo) ve sınav sonuçları (sağ tablo). LEFT JOIN ile tüm öğrencileri listelersin — sınava girmeyenlerin yanında "sınav notu: NULL" yazar. INNER JOIN olsaydı sınava girmeyenler listede görünmezdi.
LEFT JOIN (LEFT OUTER JOIN)
Sol tablonun tüm satırlarını döndürür. Sağ tabloda eşleşme yoksa sağ tablo sütunları NULL olur.
-- TÜM müşteriler + siparişleri (sipariş olmayanlar da)
SELECT c.first_name, c.last_name, o.order_id, o.total_amount
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id;+------------+-----------+----------+--------------+
| first_name | last_name | order_id | total_amount |
+------------+-----------+----------+--------------+
| Ahmet | Yılmaz | 1 | 55299.98 |
| Ahmet | Yılmaz | 2 | 1599.98 |
| Ahmet | Yılmaz | 10 | 599.99 |
| Zeynep | Kaya | 3 | 64999.99 |
| Zeynep | Kaya | 7 | 219.98 |
| Mehmet | Demir | 4 | 45299.98 |
| Deniz | Yıldız | NULL | NULL | ← Sipariş yok!
| Selin | Aydın | NULL | NULL | ← Sipariş yok!
+------------+-----------+----------+--------------+Deniz ve Selin hiç sipariş vermemiş — LEFT JOIN sayesinde listede görünüyorlar.
LEFT JOIN ile "Olmayanları" Bulma
-- Hiç sipariş vermemiş müşteriler
SELECT c.first_name, c.last_name, c.email
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;
-- Sadece eşleşmeyenler (sipariş NULL olanlar)
-- Hiç satılmamış ürünler
SELECT p.product_name, p.price
FROM products p
LEFT JOIN order_items oi ON p.product_id = oi.product_id
WHERE oi.item_id IS NULL;
-- Çalışanı olmayan departmanlar
SELECT d.department_name
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
WHERE e.employee_id IS NULL;Bu pattern çok yaygındır: LEFT JOIN + WHERE sağ_tablo.pk IS NULL = "sol tabloda olup sağ tabloda olmayan kayıtlar."
ON vs WHERE Farkı — LEFT JOIN'de Kritik!
INNER JOIN'de ON ve WHERE'e ek koşul yazmak aynı sonucu verir. LEFT JOIN'de fark yaratır:
-- ON'da ek koşul: Tüm müşteriler gösterilir, ama sadece delivered siparişler eşleştirilir
SELECT c.first_name, o.order_id, o.status
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id AND o.status = 'delivered';
-- Sipariş vermemiş müşteriler: order_id = NULL, status = NULL
-- Sipariş vermiş ama delivered olmayan: order_id = NULL, status = NULL (eşleşme yok)
-- WHERE'de ek koşul: Önce LEFT JOIN yapılır, sonra filtrelenir
SELECT c.first_name, o.order_id, o.status
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE o.status = 'delivered';
-- LEFT JOIN'in anlamı yok artık — sadece delivered siparişi olanlar döner
-- Bu aslında INNER JOIN gibi çalışır!⚠️ Dikkat: LEFT JOIN + WHERE sağ_tablo.sütun = 'değer' kullanırsan, LEFT JOIN'in "sol tablo tam" garantisi kaybolur. Eşleşmeyenler WHERE'de filtrelenir. Ek koşulları ON'a yaz.
RIGHT JOIN
RIGHT JOIN, LEFT JOIN'in tersidir: sağ tablonun tüm satırlarını döndürür.
-- TÜM siparişler + müşteri bilgisi
SELECT c.first_name, c.last_name, o.order_id
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;
-- Tüm siparişler var, müşterisi olmayan sipariş varsa müşteri bilgisi NULLPratikte RIGHT JOIN nadiren kullanılır çünkü tabloların yerini değiştirip LEFT JOIN yazmak daha okunabilir:
-- RIGHT JOIN
SELECT c.first_name, o.order_id
FROM customers c
RIGHT JOIN orders o ON c.customer_id = o.customer_id;
-- Aynı sonuç — LEFT JOIN ile (daha yaygın)
SELECT c.first_name, o.order_id
FROM orders o
LEFT JOIN customers c ON o.customer_id = c.customer_id;💡 İpucu: LEFT JOIN'i tercih et, RIGHT JOIN'den kaçın. Tabloları yer değiştirip LEFT JOIN kullanmak daha tutarlı ve okunabilir bir kod stili oluşturur.
LEFT JOIN ile Aggregate
-- Tüm müşteriler ve sipariş istatistikleri (sipariş vermeyenler dahil)
SELECT
c.customer_id,
CONCAT(c.first_name, ' ', c.last_name) AS customer_name,
COUNT(o.order_id) AS order_count, -- ⚠️ COUNT(o.order_id), COUNT(*) değil!
COALESCE(SUM(o.total_amount), 0) AS total_spent
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.first_name, c.last_name
ORDER BY total_spent DESC;⚠️ Dikkat: LEFT JOIN + COUNT kullanırken
COUNT(*)yerineCOUNT(sağ_tablo.sütun)kullan.COUNT(*)eşleşmeyen satırları da 1 sayar,COUNT(o.order_id)NULL'ları atlar (doğru sonuç).
Gerçek Dünya Örneği — Ürün Satış Analizi
-- Tüm ürünler ve satış durumları (satılmayanlar dahil)
SELECT
p.product_id,
p.product_name,
p.price,
p.stock_quantity,
COALESCE(SUM(oi.quantity), 0) AS total_sold,
COALESCE(ROUND(SUM(oi.quantity * oi.unit_price), 2), 0) AS revenue,
CASE
WHEN SUM(oi.quantity) IS NULL THEN '🔴 Hiç satılmadı'
WHEN SUM(oi.quantity) < 5 THEN '🟡 Düşük satış'
ELSE '🟢 Normal satış'
END AS sales_status
FROM products p
LEFT JOIN order_items oi ON p.product_id = oi.product_id
LEFT JOIN orders o ON oi.order_id = o.order_id AND o.status != 'cancelled'
WHERE p.is_active = TRUE
GROUP BY p.product_id, p.product_name, p.price, p.stock_quantity
ORDER BY revenue DESC;Sıkça Yapılan Hatalar
LEFT JOIN + WHERE sağ_tablo.sütun = değer: Bu LEFT JOIN'i fiilen INNER JOIN'e çevirir. Ek koşulları ON'a yaz.
COUNT(*) vs COUNT(sütun): LEFT JOIN'de COUNT(*) yanlış sonuç verir — eşleşmeyenler de 1 sayılır.
RIGHT JOIN tercih etmek: Tabloları yer değiştirip LEFT JOIN kullan — daha okunabilir.
Özet
LEFT JOIN sol tablonun tamamını döndürür, eşleşmeyen sağ sütunlar NULL olur
RIGHT JOIN sağ tablonun tamamını döndürür — ama LEFT JOIN tercih et
LEFT JOIN + WHERE sağ.pk IS NULL = "sol tabloda olup sağ tabloda olmayanlar"
LEFT JOIN'de ek filtre ON'a yazılmalı, WHERE'e değil
LEFT JOIN + COUNT kullanırken
COUNT(sağ_tablo.sütun)kullanLEFT JOIN + COALESCE ile NULL'ları anlamlı değerlerle değiştir
AI Asistan
Sorularını yanıtlamaya hazır