← Kursa Dön
📄 Text · 35 min

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 NULL

Pratikte 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(*) yerine COUNT(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

  1. LEFT JOIN + WHERE sağ_tablo.sütun = değer: Bu LEFT JOIN'i fiilen INNER JOIN'e çevirir. Ek koşulları ON'a yaz.

  2. COUNT(*) vs COUNT(sütun): LEFT JOIN'de COUNT(*) yanlış sonuç verir — eşleşmeyenler de 1 sayılır.

  3. 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) kullan

  • LEFT JOIN + COALESCE ile NULL'ları anlamlı değerlerle değiştir