← Kursa Dön
📄 Text · 35 min

INNER JOIN — Detaylı, Çoklu Tablo

Giriş — Sadece Eşleşenler

INNER JOIN, iki tabloda ortak koşulu sağlayan satırları birleştirir. Eşleşme olmayan satırlar sonuçta yer almaz. En sık kullanılan JOIN türüdür.

🎯 Analoji: İki okuldaki öğrenci listelerini düşün. INNER JOIN, her iki okulda da kayıtlı olan öğrencileri bulur. Sadece bir okulda olanlar sonuçta görünmez.


Temel INNER JOIN

-- Müşteriler ve siparişleri
SELECT c.first_name, c.last_name, o.order_id, o.total_amount, o.status
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id;

Burada:

  • customers sol tablo, orders sağ tablo

  • ON c.customer_id = o.customer_id birleştirme koşulu

  • Sipariş vermemiş müşteriler sonuçta YOKTUR

  • Müşterisi olmayan siparişler sonuçta YOKTUR (FK ile zaten imkansız)

INNER keyword'ü opsiyoneldir — JOIN tek başına INNER JOIN anlamına gelir:

-- İkisi de aynı:
SELECT c.first_name, o.order_id FROM customers c JOIN orders o ON c.customer_id = o.customer_id;
SELECT c.first_name, o.order_id FROM customers c INNER JOIN orders o ON c.customer_id = o.customer_id;

Birden Fazla Tablo ile INNER JOIN

-- Sipariş detayı: müşteri + sipariş + ürünler
SELECT 
    c.first_name,
    c.last_name,
    o.order_id,
    DATE_FORMAT(o.order_date, '%d.%m.%Y') AS order_date,
    p.product_name,
    oi.quantity,
    CONCAT('₺', FORMAT(oi.unit_price, 2)) AS price,
    CONCAT('₺', FORMAT(oi.quantity * oi.unit_price, 2)) AS line_total
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
INNER JOIN products p ON oi.product_id = p.product_id
ORDER BY o.order_id, p.product_name;

Bu sorgu 4 tabloyu zincirleme birleştirir:

customers → orders → order_items → products
    ↑          ↑          ↑            ↑
customer_id  order_id  product_id   product_id

Kategori Bilgisini de Ekleyelim

SELECT 
    c.first_name,
    o.order_id,
    cat.category_name,
    p.product_name,
    oi.quantity,
    oi.unit_price
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
INNER JOIN products p ON oi.product_id = p.product_id
INNER JOIN categories cat ON p.category_id = cat.category_id
WHERE o.status = 'delivered'
ORDER BY o.order_date DESC;

5 tablo birleştirildi — ve her JOIN bir öncekinin üzerine inşa ediliyor.


INNER JOIN ile Aggregate

-- Her müşterinin toplam sipariş tutarı
SELECT 
    c.customer_id,
    CONCAT(c.first_name, ' ', c.last_name) AS customer_name,
    COUNT(o.order_id) AS order_count,
    ROUND(SUM(o.total_amount), 2) AS total_spent
FROM customers c
INNER 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;

-- Her kategorinin satış performansı
SELECT 
    cat.category_name,
    COUNT(DISTINCT oi.order_id) AS order_count,
    SUM(oi.quantity) AS units_sold,
    ROUND(SUM(oi.quantity * oi.unit_price), 2) AS revenue
FROM categories cat
INNER JOIN products p ON cat.category_id = p.category_id
INNER JOIN order_items oi ON p.product_id = oi.product_id
GROUP BY cat.category_id, cat.category_name
ORDER BY revenue DESC;

ON Koşulunda Ek Filtreler

-- Sadece teslim edilmiş siparişlerle JOIN
SELECT c.first_name, o.order_id, o.total_amount
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id AND o.status = 'delivered';

-- vs WHERE'de filtreleme (INNER JOIN'de sonuç aynı)
SELECT c.first_name, o.order_id, o.total_amount
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
WHERE o.status = 'delivered';

💡 İpucu: INNER JOIN'de ek koşulu ON'a veya WHERE'e yazmak aynı sonucu verir. Ama LEFT JOIN'de fark yaratır — bunu bir sonraki derste göreceğiz.


USING Kısayolu

İki tablodaki birleştirme sütunu aynı isme sahipse USING kullanabilirsin:

-- ON yerine USING
SELECT c.first_name, o.order_id
FROM customers c
INNER JOIN orders o USING (customer_id);
-- = ON c.customer_id = o.customer_id

Gerçek Dünya Örneği — Sipariş Faturası

-- Fatura detayı
SELECT 
    CONCAT('FAT-', LPAD(o.order_id, 6, '0')) AS fatura_no,
    DATE_FORMAT(o.order_date, '%d.%m.%Y %H:%i') AS tarih,
    CONCAT(c.first_name, ' ', c.last_name) AS musteri,
    c.email,
    p.product_name AS urun,
    oi.quantity AS adet,
    CONCAT('₺', FORMAT(oi.unit_price, 2)) AS birim_fiyat,
    CONCAT('₺', FORMAT(oi.quantity * oi.unit_price, 2)) AS satir_toplam
FROM orders o
INNER JOIN customers c ON o.customer_id = c.customer_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
INNER JOIN products p ON oi.product_id = p.product_id
WHERE o.order_id = 1
ORDER BY oi.item_id;

Sıkça Yapılan Hatalar

  1. Kartezyen çarpım: ON koşulu yanlış yazılırsa beklenenden çok fazla satır döner. Her JOIN'in doğru FK-PK eşleşmesi yaptığını kontrol et.

  2. Performans: Her ek JOIN maliyettir. Gereksiz JOIN yapma — sadece ihtiyacın olan tabloları birleştir.

  3. Ambiguous column: İki tabloda aynı isimli sütun varsa c.customer_id gibi prefix kullan.


Özet

  • INNER JOIN sadece her iki tabloda da eşleşen satırları döndürür

  • JOIN = INNER JOIN (INNER opsiyonel)

  • Birden fazla INNER JOIN zincirleme kullanılabilir (3, 4, 5+ tablo)

  • USING, sütun adları aynı olduğunda kısa yol sağlar

  • ON'daki ek koşullar INNER JOIN'de WHERE ile aynı sonucu verir

  • Her JOIN doğru FK-PK eşleşmesi kullanmalı