İçindekiler
İlişkisel veritabanlarında veriler farklı tablolara bölünür: müşteriler bir tabloda, siparişler başka bir tabloda. Bir müşterinin siparişlerini ya da siparişleri veren müşterilerin adlarını görmek istediğinizde bu tabloları birleştirmeniz (JOIN) gerekir.
Örnek tablolarımız:
musteriler siparisler
+----+---------+ +----+-------------+--------+
| id | ad | | id | musteri_id | tutar |
+----+---------+ +----+-------------+--------+
| 1 | Ayşe | | 10 | 1 | 250 |
| 2 | Mehmet | | 11 | 1 | 120 |
| 3 | Zeynep | | 12 | 2 | 900 |
+----+---------+ | 13 | 9 | 75 |
+----+-------------+--------+
Dikkat edin: Zeynep'in hiç siparişi yok. 13 numaralı sipariş ise artık var olmayan 9 numaralı bir müşteriye ait (veri tutarsızlığı; gerçek hayatta da olur).
INNER JOIN: Yalnızca eşleşenler
SELECT m.ad, s.id AS siparis, s.tutar
FROM musteriler m
INNER JOIN siparisler s ON s.musteri_id = m.id;
Ayşe 10 250
Ayşe 11 120
Mehmet 12 900
Yalnızca her iki tabloda da karşılığı olan satırlar döner. Zeynep (siparişi yok) ve 13 numaralı sipariş (müşterisi yok) sonuçta görünmez. Yalnızca JOIN yazmak da INNER JOIN anlamına gelir.
LEFT JOIN: Soldakilerin hepsi
SELECT m.ad, s.id AS siparis, s.tutar
FROM musteriler m
LEFT JOIN siparisler s ON s.musteri_id = m.id;
Ayşe 10 250
Ayşe 11 120
Mehmet 12 900
Zeynep NULL NULL
Soldaki tablonun (musteriler) bütün satırları döner. Sağda karşılığı olmayanlar için sağ tablonun sütunları NULL olur.
LEFT JOIN'in en kullanışlı uygulamalarından biri, karşılığı olmayanları bulmaktır. Örneğin hiç sipariş vermemiş müşteriler:
SELECT m.ad
FROM musteriler m
LEFT JOIN siparisler s ON s.musteri_id = m.id
WHERE s.id IS NULL;
Zeynep
RIGHT JOIN: Sağdakilerin hepsi
SELECT m.ad, s.id AS siparis, s.tutar
FROM musteriler m
RIGHT JOIN siparisler s ON s.musteri_id = m.id;
Ayşe 10 250
Ayşe 11 120
Mehmet 12 900
NULL 13 75
LEFT JOIN'in tersidir. Pratikte pek kullanılmaz, çünkü tabloların yerini değiştirip LEFT JOIN yazmak daha okunaklıdır. Bu örnek, müşterisi silinmiş "yetim" siparişleri bulmak için işe yarar.
FULL OUTER JOIN
Her iki tablonun bütün satırlarını, eşleşmeyenleri de dahil ederek döndürür. PostgreSQL ve SQL Server destekler. MySQL ve MariaDB desteklemez; aynı sonucu LEFT JOIN ile RIGHT JOIN'i UNION ile birleştirerek elde edebilirsiniz.
Sık yapılan hatalar
1. LEFT JOIN'i WHERE ile INNER JOIN'e çevirmek
-- Amaç: Bütün müşteriler ve 2026'daki siparişleri
SELECT m.ad, s.tutar
FROM musteriler m
LEFT JOIN siparisler s ON s.musteri_id = m.id
WHERE s.tarih >= '2026-01-01';
Bu sorgu, 2026'da siparişi olmayan müşterileri sonuçtan çıkarır. Çünkü onlar için s.tarih değeri NULL olur ve WHERE koşulu sağlanmaz. LEFT JOIN, farkında olmadan INNER JOIN'e dönüşür.
Doğrusu, sağ tabloya ait koşulu ON kısmına yazmaktır:
SELECT m.ad, s.tutar
FROM musteriler m
LEFT JOIN siparisler s ON s.musteri_id = m.id AND s.tarih >= '2026-01-01';
Kural: LEFT JOIN'de sağ tabloyu filtreleyen koşullar ON'a, sol tabloyu filtreleyen koşullar WHERE'e yazılır.
2. Satırların katlanması
SELECT m.ad, SUM(s.tutar) AS toplam, COUNT(a.id) AS adres_sayisi
FROM musteriler m
LEFT JOIN siparisler s ON s.musteri_id = m.id
LEFT JOIN adresler a ON a.musteri_id = m.id
GROUP BY m.id;
Ayşe'nin 2 siparişi ve 3 adresi varsa, birleştirme 2 × 3 = 6 satır üretir. Sipariş toplamı üç kat, adres sayısı iki kat fazla hesaplanır. Bu hata özellikle sinsidir, çünkü sorgu hata vermez; yalnızca yanlış sayılar döner.
Çözüm, toplamları ayrı ayrı hesaplayıp sonra birleştirmektir:
SELECT m.ad, s.toplam, a.adres_sayisi
FROM musteriler m
LEFT JOIN (SELECT musteri_id, SUM(tutar) toplam FROM siparisler GROUP BY musteri_id) s ON s.musteri_id = m.id
LEFT JOIN (SELECT musteri_id, COUNT(*) adres_sayisi FROM adresler GROUP BY musteri_id) a ON a.musteri_id = m.id;
3. ON koşulunu unutmak
ON koşulu eksik ya da yanlış yazılırsa, her satır diğer tablonun her satırıyla eşleşir (kartezyen çarpım). 10.000 müşteri ve 100.000 sipariş, bir milyar satır demektir. Sunucuyu kilitleyen sorguların klasik sebeplerinden biridir.
4. İndeks olmadan JOIN
ON s.musteri_id = m.id koşulundaki musteri_id sütununda indeks yoksa, veritabanı her müşteri için bütün sipariş tablosunu tarar. Yabancı anahtar sütunlarına her zaman indeks ekleyin. InnoDB, bir yabancı anahtar kısıtı tanımladığınızda bunu otomatik yapar.
Hangi JOIN?
- Yalnızca ilişkisi olan kayıtlar → INNER JOIN
- Ana tablonun bütün kayıtları, ilişkisi olsun olmasın → LEFT JOIN
- Karşılığı olmayanları bulmak → LEFT JOIN + WHERE ... IS NULL
Yeni bir JOIN sorgusu yazdığınızda, sonucun satır sayısını mantıklı bir beklentiyle karşılaştırmayı alışkanlık hâline getirin. Beklediğinizden az satır kayıp kayıtları, fazla satır ise katlanmayı gösterir.
Yorumlar
Henüz yorum yok. İlk yorumu siz yazın.