İçeriğe geç
academia.sh

Ders 08 / 18

Dış Birleştirmeler

Eşleşmesi olmayan satırların korunması, korunan satırların boş değerle dolması, eşleşmeyeni bulan kalıp, sağ ve tam dış birleştirmenin motor desteği ve koşulun yerinin sonucu değiştirmesi.

İçindekiler

Önceki ders iç birleştirmenin bir sınırını gösterdi: koşulu sağlamayan satır sonuçta hiç görünmez. Kitaplar şubelerle birleştirildiğinde şubesi belirlenmemiş kitap düştü, sonuç yedi yerine altı satır oldu.

Kimi sorular tam da o düşen satırları arar. “Hangi şubede hiç kitap yok”, “hangi üye hiç ödünç almamış”, “hangi kitap hiç kimse tarafından alınmamış” — üçü de eşleşmesi olmayan satırları soruyor. İç birleştirme bunları yanıtlayamaz, çünkü aradığı şeyi zaten eliyor. Bu ders eşleşmesi olmayan satırları koruyan birleştirme türünü kurar.

Aşağıdaki blok şemayı ve örnek veriyi kurar; dersin bütün sorguları bu blokta oluşturulan kutuphane.db dosyası üzerinde çalışır.

rm -f kutuphane.db
sqlite3 kutuphane.db <<'SQL'
CREATE TABLE sube (sube_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, sehir TEXT NOT NULL);
CREATE TABLE kitap (kitap_id INTEGER PRIMARY KEY, baslik TEXT NOT NULL, yazar TEXT NOT NULL,
                    basim_yili INTEGER, sube_id INTEGER REFERENCES sube(sube_id));
CREATE TABLE uye (uye_id INTEGER PRIMARY KEY, ad TEXT NOT NULL, soyad TEXT NOT NULL,
                  eposta TEXT, kayit_tarihi TEXT NOT NULL);
CREATE TABLE odunc (odunc_id INTEGER PRIMARY KEY, kitap_id INTEGER NOT NULL REFERENCES kitap(kitap_id),
                    uye_id INTEGER NOT NULL REFERENCES uye(uye_id), alis_tarihi TEXT NOT NULL,
                    iade_tarihi TEXT);
INSERT INTO sube VALUES (1,'Merkez','Ankara'),(2,'Bahçelievler','Ankara'),
  (3,'Kadıköy','İstanbul'),(4,'Konak','İzmir');
INSERT INTO kitap VALUES (1,'Körlük','José Saramago',1995,1),(2,'Tutunamayanlar','Oğuz Atay',1972,1),
  (3,'Kum Kitabı','Jorge Luis Borges',1975,2),(4,'Yaban','Yakup Kadri',1932,2),
  (5,'Sessiz Ev','Orhan Pamuk',1983,3),(6,'Anayurt Oteli','Yusuf Atılgan',NULL,3),
  (7,'Tehlikeli Oyunlar','Oğuz Atay',1973,NULL);
INSERT INTO uye VALUES (1,'Ayşe','Demir','[email protected]','2023-02-14'),
  (2,'Mehmet','Kaya','[email protected]','2023-05-30'),(3,'Zeynep','Arslan',NULL,'2024-01-09'),
  (4,'Emre','Yıldız','[email protected]','2024-03-22'),(5,'Selin','Aydın',NULL,'2024-11-05'),
  (6,'Burak','Şahin','[email protected]','2025-01-18');
INSERT INTO odunc VALUES (1,1,1,'2025-01-10','2025-01-24'),(2,2,1,'2025-02-02','2025-02-20'),
  (3,1,2,'2025-02-11',NULL),(4,3,3,'2025-03-01','2025-03-15'),(5,4,3,'2025-03-18','2025-04-02'),
  (6,1,4,'2025-04-05','2025-04-19'),(7,5,4,'2025-04-21',NULL),(8,2,5,'2025-05-02','2025-05-30'),
  (9,7,1,'2025-05-14','2025-05-28'),(10,3,5,'2025-06-03',NULL),(11,6,2,'2025-06-11','2025-06-25'),
  (12,4,4,'2025-06-20','2025-07-04');
SQL

Sol Dış Birleştirme

Sol dış birleştirme (left outer join), soldaki tablonun bütün satırlarını korur. Sağdaki tabloda eşleşme bulunmayan satırlar için sağ tablonun sütunları boş değerle doldurulur.

sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT k.baslik, s.ad AS sube
FROM kitap AS k
LEFT JOIN sube AS s ON k.sube_id = s.sube_id
ORDER BY k.kitap_id;
SQL
baslik             sube        
-----------------  ------------
Körlük             Merkez      
Tutunamayanlar     Merkez      
Kum Kitabı         Bahçelievler
Yaban              Bahçelievler
Sessiz Ev          Kadıköy     
Anayurt Oteli      Kadıköy     
Tehlikeli Oyunlar              

Yedi kitabın hepsi döndü. Tehlikeli Oyunlar satırında şube adı boş: kitap korundu, ama eşleşme olmadığı için sağ tablodan gelen sütun dolduramadı. OUTER sözcüğü isteğe bağlıdır; LEFT JOIN ile LEFT OUTER JOIN aynı şeydir.

Boş değerin kaynağı burada önemlidir. Şube adı sütunu NOT NULL tanımlı olduğu için şube tablosunda hiç boş ad yok. Sonuçtaki boşluk veriden gelmiyor, birleştirmenin kendisi üretti. Dış birleştirme sonucundaki boş değer iki farklı şeyi gösterebilir: ya kaynak satırda gerçekten boş bir değer vardı, ya da hiç eşleşme yoktu. Ayrım gerektiğinde eşleşmenin varlığı, sağ tablonun birincil anahtarı sınanarak anlaşılır.

Yön değiştirildiğinde korunan taraf da değişir.

sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT s.ad AS sube, k.baslik
FROM sube AS s
LEFT JOIN kitap AS k ON k.sube_id = s.sube_id
ORDER BY s.sube_id, k.kitap_id;
SQL
sube          baslik        
------------  --------------
Merkez        Körlük        
Merkez        Tutunamayanlar
Bahçelievler  Kum Kitabı    
Bahçelievler  Yaban         
Kadıköy       Sessiz Ev     
Kadıköy       Anayurt Oteli 
Konak                       

Şimdi bütün şubeler görünüyor; hiç kitabı olmayan Konak da listede, kitap sütunu boş. Aynı iki tablo, aynı koşul, farklı korunan taraf.

Eşleşmeyeni Bulmak

Dış birleştirmenin en çok kullanılan kalıbı, korunan ama eşleşmeyen satırları ayıklamaktır. Eşleşme yoksa sağ tablonun bütün sütunları boş olacağına göre, sağ tablonun birincil anahtarını boşluk için sınamak bu satırları seçer.

sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT s.ad AS kitapsiz_sube
FROM sube AS s
LEFT JOIN kitap AS k ON k.sube_id = s.sube_id
WHERE k.kitap_id IS NULL;
SQL
kitapsiz_sube
-------------
Konak        

Aynı kalıp üyelere uygulanır.

sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT u.ad, u.soyad
FROM uye AS u
LEFT JOIN odunc AS o ON o.uye_id = u.uye_id
WHERE o.odunc_id IS NULL;
SQL
ad     soyad
-----  -----
Burak  Şahin

Sınamanın birincil anahtar üzerinde yapılması gerektiğine dikkat edilmelidir. Boş değer kabul eden bir sütun sınansaydı sonuç yanlış olurdu: o sütunun gerçekten boş olduğu eşleşen satırlar da listeye karışırdı. Birincil anahtar hiçbir zaman boş olamayacağı için, boş görünmesi tek bir anlama gelir — eşleşme yok.

Sağ ve Tam Dış Birleştirme

Sol dış birleştirmenin aynadaki karşılığı sağ dış birleştirmedir (right outer join): sağdaki tablonun satırları korunur.

sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT s.ad AS sube, k.baslik
FROM kitap AS k
RIGHT JOIN sube AS s ON k.sube_id = s.sube_id
ORDER BY s.sube_id, k.kitap_id;
SQL
sube          baslik        
------------  --------------
Merkez        Körlük        
Merkez        Tutunamayanlar
Bahçelievler  Kum Kitabı    
Bahçelievler  Yaban         
Kadıköy       Sessiz Ev     
Kadıköy       Anayurt Oteli 
Konak                       

Sonuç, bir önceki bölümdeki sube LEFT JOIN kitap sorgusuyla aynı. Bu bir rastlantı değil: her sağ dış birleştirme, tablo sırası ters çevrilerek sol dış birleştirmeye dönüştürülebilir. İki yazım arasında anlam farkı yoktur.

Bu eşdeğerlik pratik bir değer taşır, çünkü sağ dış birleştirme desteği motora göre değişir — bazı motorlar yalnız sol dış birleştirmeyi gerçekleştirir. Sorgu sol biçimde yazıldığında taşınabilirlik sorunu ortadan kalkar. Okunabilirlik açısından da sol biçim tercih edilir: korunan tablo FROM yan tümcesinde, yani okuma sırasında ilk görülen yerde durur.

Tam dış birleştirme (full outer join) iki tarafın da eşleşmeyen satırlarını korur.

sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT s.ad AS sube, k.baslik
FROM kitap AS k
FULL OUTER JOIN sube AS s ON k.sube_id = s.sube_id
ORDER BY s.sube_id, k.kitap_id;
SQL
sube          baslik           
------------  -----------------
              Tehlikeli Oyunlar
Merkez        Körlük           
Merkez        Tutunamayanlar   
Bahçelievler  Kum Kitabı       
Bahçelievler  Yaban            
Kadıköy       Sessiz Ev        
Kadıköy       Anayurt Oteli    
Konak                          

Sekiz satır: altı eşleşme, şubesi olmayan bir kitap ve kitabı olmayan bir şube. İki yönün eksikleri tek sonuçta toplandı.

Tam dış birleştirmenin desteği de motora göre değişir ve sağ dış birleştirmeden daha seyrek bulunur. Bulunmadığı yerde eşdeğer yazım, sol dış birleştirme ile ters yönlü sol dış birleştirmenin birleşimidir; küme işlemleri bu konunun son dersinde ele alınacak.

Koşulun Yeri Sonucu Değiştirir

Dış birleştirmede en sık yapılan yanlış, sağ tabloya ait bir koşulu ON yerine WHERE içine yazmaktır. İç birleştirmede iki yazım aynı sonucu verir; dış birleştirmede vermez.

Önce koşul birleştirmenin içinde:

sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT u.ad, u.soyad, o.odunc_id, o.alis_tarihi
FROM uye AS u
LEFT JOIN odunc AS o ON o.uye_id = u.uye_id AND o.alis_tarihi >= '2025-05-01'
ORDER BY u.uye_id, o.odunc_id;
SQL
ad      soyad   odunc_id  alis_tarihi
------  ------  --------  -----------
Ayşe    Demir   9         2025-05-14 
Mehmet  Kaya    11        2025-06-11 
Zeynep  Arslan                       
Emre    Yıldız  12        2025-06-20 
Selin   Aydın   8         2025-05-02 
Selin   Aydın   10        2025-06-03 
Burak   Şahin                        

Altı üyenin hepsi listede. Koşulu sağlayan ödünç kaydı olmayan iki üye korundu ve ödünç sütunları boş kaldı.

Şimdi aynı koşul süzme yan tümcesinde:

sqlite3 kutuphane.db <<'SQL'
.headers on
.mode column
SELECT u.ad, u.soyad, o.odunc_id, o.alis_tarihi
FROM uye AS u
LEFT JOIN odunc AS o ON o.uye_id = u.uye_id
WHERE o.alis_tarihi >= '2025-05-01'
ORDER BY u.uye_id, o.odunc_id;
SQL
ad      soyad   odunc_id  alis_tarihi
------  ------  --------  -----------
Ayşe    Demir   9         2025-05-14 
Mehmet  Kaya    11        2025-06-11 
Emre    Yıldız  12        2025-06-20 
Selin   Aydın   8         2025-05-02 
Selin   Aydın   10        2025-06-03 

İki üye kayboldu. Nedeni beşinci dersteki kuraldır: birleştirme korunan satırların ödünç sütunlarını boş değerle doldurdu, WHERE yan tümcesi ise bu satırlarda NULL >= '2025-05-01' karşılaştırmasını değerlendirdi ve sonuç bilinmeyen çıktı. WHERE yalnız doğruyu geçirir, dolayısıyla korunan satırlar elendi.

Kural şöyle özetlenir: ON yan tümcesi hangi satırların eşleştiğini, WHERE yan tümcesi birleştirme bittikten sonra hangi satırların kalacağını belirler. Sağ tabloya ait bir koşul WHERE içine yazıldığında dış birleştirme sessizce iç birleştirmeye döner. Bu dönüşümün tek istisnası, kasten yazılan boşluk sınamasıdır — eşleşmeyeni bulan kalıp tam da bu etkiyi kullanır.

Özet

  • Sol dış birleştirme soldaki tablonun bütün satırlarını korur ve eşleşme yoksa sağ tablonun sütunlarını boş değerle doldurur.
  • Sonuçtaki boş değer ya kaynaktan gelir ya da birleştirmenin kendisi üretmiştir; ayrım sağ tablonun birincil anahtarı sınanarak yapılır.
  • Eşleşmeyen satırları bulan kalıp, dış birleştirmeden sonra sağ tablonun birincil anahtarını boşluk için sınamaktır.
  • Her sağ dış birleştirme, tablo sırası ters çevrilerek sol dış birleştirmeye dönüşür; sağ ve tam dış birleştirmenin desteği motora göre değişir.
  • Tam dış birleştirme iki tarafın da eşleşmeyen satırlarını korur.
  • Sağ tabloya ait koşul WHERE içine yazıldığında dış birleştirme sessizce iç birleştirmeye döner; koşul ON içinde yazılmalıdır.

Sonraki Adım

Buraya kadarki birleştirmelerin hepsi bir eşitlik koşuluna dayandı. Koşulun kendisi kaldırılırsa ne olur, ya da bir tablo kendisiyle birleştirilirse? Sonraki ders bu iki özel durumu ele alır: koşulsuz birleştirmenin ürettiği çarpım ve bir tablonun iki farklı takma adla kendisine bağlanmasıyla kurulan karşılaştırmalar.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat