5 Aralık 2020 Cumartesi

SQL'de Join Çeşitleri

Merhaba Arkadaşlar,

Temel bir konuya değinmek istiyorum bugün. Zira mail üstünden gelen sorularda özellikle işin outer join kısmında bir kafa karışıklığı olduğu görülüyor. Oracle üzerinden anlatacağım konuları, gidişata göre ayrı başlıklar da açabilirim.

JOIN dediğimiz kavram, birden fazla tablodan veri almamızı sağlayan ifadeler, bağlaçlardır. 

JOIN sorgusu çalıştırırken, Oracle'da Optimizer'ın bazı kontrolleri vardır. Join'i yaparken index kullanılacak mı; full table scan mı gidecek(yani tüm tabloyu tek tek gezecek mi; yoksa nokta atışı yapacak mı gibi çevirebilirim burayı), bunu belirler. Akabinde join'e giren tablo sayısı 2'den fazlaysa, join order'ı yapar. Yani önce küçük tabloları joinler, sonra buradan dönen data set'i üstünden büyük tabloya gider. Bu sayede sorgu performansında artış amaçlanır. Son olarak da yazdığımız join'e bağlı olarak arka planda hangi join method'u(hash-sort merge-nested loop) kullanılır, bu belirlenir. Yöntemlere kısaca ayrı bir başlıkta değineceğim.

Gelelim sql önyüzünde, Toad-plsql developer-sql plus gibi bir arayüzde yazdığınız join türlerine.
1. Inner Join
2. Left Join (Left Outer Join)
3. Right Join (Right Outer Join)
4. Full Join (Full Outer Join)

Öncelikle örnekte kullanmka üzere iki tablo yaratalım.
JoinTableTest1 tablosu takım bilgisi tutuyor olsun.

JoinTableTest2 tablosu da oyuncuları tutuyor olsun; TakımID de foreign key'i ve bu kolon üstünden join kuralım. Tablolar ve alanlar çok uyduruk. :) Joini anlatmak için hızlıca oluşturdum, mantıksal tasarımı sıkıntılı; join'e odaklanın lütfen. :)


INNER JOIN:
İki tablonun joininde eşleşen kayıtlar için sonuç döndüren join türüdür. 
select t1.TakimAdi,t2.OyuncuAdi from JoinTableTest1 t1, JoinTableTest2 t2
where  t1.TakimID=t2.TakimID --bu eşitlikle inner join veriyoruz.
--Yani her iki tabloda TakimID'si eşit olan oyuncuları getiriyor. 


İnternetten aldığım resimle olayı açıklıyorum. 
Örneğimizde iki tabloda takımIDsi aynı olan kayıtlar getiriliyor.

Aynı sorguyu = operatoru yerine, INNER JOIN ile de yazabilirsiniz:
select t1.TakimAdi,t2.OyuncuAdi 
from JoinTableTest1 t1 INNER JOIN JoinTableTest2 t2
ON t1.TakimID=t2.TakimID

Bu da aynı sonucu üretir:



LEFT JOIN:
Kitabi anlatmayacağım. :) Joinin solundaki tablonun tamamı listelenir. Olayın mantığının temeli bu. Eğer select ifadesinde, sağdaki ikinci tablodan kolonlar varsa, solda olup, sağda karşılığı olmayan kayıtlar için, selectteki o kolonlar null gelir. Örnekle açıklamak en güzeli. :)

select t1.TakimAdi,t2.OyuncuAdi 
from JoinTableTest1 t1 LEFT JOIN JoinTableTest2 t2
ON t1.TakimID=t2.TakimID 

Şimdi örnek üstünden açıklayalım. Soldaki tablo nedir: JoinTableTest1. Bu tabloda takımlar vardı. Demek ki eşleşse de eşleşmese de, bu tablonun tüm kayıtları gelecek. Eşleşen 11 kayıt, zaten inner join'de de görmüştük, kafadan gelmiş. Ancak son 2 kayda dikkat buyurun. Oyuncuları tutan JoinTableTest2 tablosunda Trabzonspor ve Galatasaray'lı oyuncu yoktu. Yani eşleşme yok. Bu nedenle OyuncuAdı alanları NULL bir şekilde, bu iki takım da gösterilmiş. Left Join tam olarak böyle bir dünya. :)

Bu sorguyu ben yukarıdaki gibi yazmaya üşeniyorum. (+) ile yazıyorum. Bu şekilde yazmak isteyeneler için:
select t1.TakimAdi,t2.OyuncuAdi 
from JoinTableTest1 t1, JoinTableTest2 t2
where t1.TakimID=t2.TakimID(+)

Eşitliğin t2 kısmına (+) konmuş. Demek ki t1'in hepsini alacağız, şeklinde aklınızda da tutabilirsiniz. :)
Oracle docs'u yerle yeksan ettik. Kendimi eski hbb kanalındaki beyin egzersizci abimiz gibi hissettim. :)

Şekilsel gösterimi de şöyle:



RIGHT JOIN:
Joinin sağındaki tablonun tamamı listelenir. Left'in aynı mantığı var burada da. Eğer select ifadesinde, soldaki birinci tablodan kolonlar varsa, sağda olup, solda karşılığı olmayan kayıtlar için, selectteki o kolonlar null gelir. Ben direkt örneğe geçeyim; en temiz öyle anlaşılır.

select t1.TakimAdi,t2.OyuncuAdi 
from JoinTableTest1 t1 RIGHT JOIN JoinTableTest2 t2
ON t1.TakimID=t2.TakimID


Sağdaki tablomuz nedir: JoinTableTest2. Oyuncu bilgilerini tutan tablo. Eşleşen 11 kayıt yine geliyor. İlave olarak sağdaki oyuncu tablosunda TakımID'si 21 ve 26 olan iki oyuncu bilgisi de geliyor. Yalnız bu takımID'ler, JoinTableTest1 tablosunda yok. Bu nedenle TakımAdı bilgisi boş geliyor. Ancak sağdaki tablonun tüm kayıtları listelendiğinden, Nouma ve İlhan kayıtları, eşleşmese de sonuç kümesinde geliyor.

Tıpkı Left Join'de olduğu gibi, Right Join'de de, aşağıdaki gibi yazabilirsiniz.
select t1.TakimAdi,t2.OyuncuAdi 
from JoinTableTest1 t1, JoinTableTest2 t2
where t1.TakimID(+)=t2.TakimID


Aynı şekilde, t1'in yanında (+) olduğundan, t2'nin hepsi listelenir gibi düşünebilirsiniz.
Şeklini de verelim right outer join'in:


FULL JOIN:
Left Join ve Right Join'in birleşimi gibi düşünülebilinir. İki tablodaki tüm kayıtlar döner. Karşılığı olmayan kayıtlar için, alanlar NULL döner.

select t1.TakimAdi,t2.OyuncuAdi 
from JoinTableTest1 t1 FULL JOIN JoinTableTest2 t2
ON t1.TakimID=t2.TakimID


Gördüğünüz üzere, hem right'taki hem de left'teki kayıtları getirdi. 
Bu join tipini de şu şekilde görselleştirebiliriz; tabi ki kaynak yine internet:

Optimizer'da görülecek olan join tiplerine daha sonra değinelim; okunurluk düşüyor.

Sonra görüşürüz.





Hiç yorum yok: