SQL Server’da Join Türleri
Birden fazla tabloyu birbirine tablolardaki eş kolonlar aracılığıyla eşitleyerek bağlayıp tek bir sonuç kümesinde değiştirme işlemlerini join’leri kullanarak gerçekleştirebiliriz. Birkaç çeşidi vardır. Kullandığımız join çeşidine göre gelen sonuç kümesi değişecektir.
Konuyu daha net anlamak için bir örnek üzerinden gidelim. Aşağıdaki script yardımıyla iki tablo oluşturup içine bazı kayıtlar ekleyeceğiz. Tablomuzun biri Şehirler tablosu olacak ve şehir isimleri yer alacak. Diğer tabloda ise şehirlerin meşhur yiyecekleri olacak.
CREATE TABLE Sehirler( ID int, SehirIsmi varchar(100) ) CREATE TABLE MeshurYiyecekler( ID int, SehirID int, YiyecekIsmi varchar(100) ) USE [Test] GO INSERT INTO [dbo].[Sehirler]([ID],[SehirIsmi])VALUES (1,'Adana') INSERT INTO [dbo].[Sehirler]([ID],[SehirIsmi])VALUES (42,'Konya') INSERT INTO [dbo].[Sehirler]([ID],[SehirIsmi])VALUES (3,'Afyon') GO INSERT INTO [dbo].[MeshurYiyecekler]([ID],[SehirID],[YiyecekIsmi])VALUES (1,1,'Kebap') INSERT INTO [dbo].[MeshurYiyecekler]([ID],[SehirID],[YiyecekIsmi])VALUES (2,42,'Etli Ekmek') INSERT INTO [dbo].[MeshurYiyecekler]([ID],[SehirID],[YiyecekIsmi])VALUES (3,3,'Kaymak')
Script’te gördüğünüz gibi MeshurYiyecekler tablosunda SehirID isminde bir kolon var. Ve MeshurYiyecekler tablosundaki SehirID kolonu ile Sehirler tablosundaki ID kolonu değerleri birbiri ile ilişkili. Bu iki tabloyu join yapmak için bu iki kolonu kullanacağız. TSQL ile script yazarken aşağıdaki join çeşitlerini kullanabiliriz.
- JOIN ya da INNER JOIN(ikisi aynı şeyi ifade eder)
- OUTER JOIN
- LEFT JOIN ya da LEFT OUTER JOIN(ikisi aynı şeyi ifade eder)
- RIGHT JOIN ya da RIGHT OUTER JOIN(ikisi aynı şeyi ifade eder)
- FULL JOIN ya da FULL OUTER JOIN(ikisi aynı şeyi ifade eder)
- CROSS JOIN
Aşağıdaki ekran görüntüsü join tiplerinin tabloları nasıl bağladığını anlamımızı kolaylaştırıyor.
Ekran görüntüsünü aldığım kaynağa aşağıdaki linkten ulaşabilirsiniz.
https://www.codeproject.com/articles/33052/visual-representation-of-sql-joins
Listediğim join türlerinin detaylarını aşağıda bulabilirsiniz.
JOIN ya da INNER JOIN: iki tablodaki ortak kayıtları getirir. Makalenin başında oluşturduğumuz iki tabloyu inner join ile birbirine aşağıdaki şekilde bağlayabiliriz. Sehir tablosundaki ID kolonu ile MeshurYiyecekler tablosundaki SehirID kolonu eşit olan kayıtları getir diyerek hangi meşhur yiyeceğin hangi şehre ait olduğunu gösteren bir sonuç elde ettik.
select * from Sehirler GO select * from MeshurYiyecekler GO select s.SehirIsmi,my.YiyecekIsmi from Sehirler s INNER JOIN MeshurYiyecekler my ON s.ID=my.SehirID
Eğer Sehirler tablosuna bir kayıt eklesek ve bu sehre ait meşhur yiyeceği MeshurYiyecekler tablosuna eklemesek join işlemi sırasında bu kayıt gelmez.
Test yapmak için Sehirler tablosuna bir kayıt ekleyelim ama MeshurYiyecekler tablosuna ilgili şehrin meşhur yiyeceğini eklemeyelim.
INSERT INTO [dbo].[Sehirler]([ID],[SehirIsmi])VALUES(27,'Gaziantep')
Biraz önce çalıştırdığımız INNER JOIN script’ini tekrar çalıştırdığımızda gördüğünüz gibi Gaziantep ile ilgili bir kayıt gelmedi.
Sehirler tablosunun sonundaki “s” ve MeshurYiyecekler tablosunun sonundaki “my” ifadelerine alias denir. Bu şekilde script’lerinizi daha anlaşılır bir şekilde yazabilirsiniz. Aşağıdaki script’te de gördüğünüz gibi alias tanımlamışsak select kısmında da alias’ları kullanarak ihtiyacımız olan kolonları çekmemiz gerekir. Alias’ın diğer bir amacı da iki tabloda da aynı isme ait bir kolon varsa ve alias tanımlamadan select kısmında direk kolonun ismini yazarsanız aşağıdaki gibi bir hata alırsınız.
Alias’sız sorgumuzda aynı isme sahip ID kolonunu çekmeyece çalıştığımızda aldığımız hata:
select ID,SehirIsmi,YiyecekIsmi from Sehirler s INNER JOIN MeshurYiyecekler my ON s.ID=my.SehirID
Msg 209, Level 16, State 1, Line 2
Ambiguous column name ‘ID’.
OUTER JOIN: INNER JOIN gibi tablolar arasında birbiri ile ilişkili kolonları kullanarak ortak kayıtları getirir. INNER JOIN’den farklı olarak karşılığı olmayan satırlar da gelir. OUTER JOIN’i tek başına OUTER JOIN yazarak kullanamazsınız. LEFT OUTER JOIN, RIGHT OUTER JOIN ya da FULL OUTER JOIN olarak kullanabilirsiniz.
LEFT JOIN ya da LEFT OUTER JOIN(ikisi aynı şeyi ifade eder): ilk tablodaki kayıtlar tamamen listelenir. Eğer ilk tablodaki kaydın karşılığı ikinci tabloda yoksa ikinci tablodaki değeri null olarak döner. Örneğin INNER JOIN’de yaptığımız örnekte Gaziantep’i Sehirler tablosuna girmiştik fakat MeshurYiyecek tablosuna Gaziantep ile ilgili bir kayıt girmediğimiz için INNER JOIN’de listelenmemişti. Aynı sorguda INNER JOIN yazan yere LEFT JOIN ya da LEFT OUTER JOIN yazarak çalıştıralım.
select s.SehirIsmi,my.YiyecekIsmi from Sehirler s LEFT OUTER JOIN MeshurYiyecekler my ON s.ID=my.SehirID
Aşağıda gördüğünüz gibi Gaziantep değeri geldi ve MeshurYiyecekler tablosundaki YiyecekIsmi kolonu ise herhangi bir kayıt olmadığı için null olarak geldi.
Bu sorguyu where koşulunda filtleyerek farklı ihtiyaçlarınızı karşılayabilirsiniz. Örneğin Sehir ismi girilen ama bu şehir ile alakalı meshur yiyeceği olmayan ya da girişi yapılmayan kayıtları listelemek istersek aşağıdaki sorguyu yazabiliriz.
select s.SehirIsmi,my.YiyecekIsmi from Sehirler s LEFT OUTER JOIN MeshurYiyecekler my ON s.ID=my.SehirID where my.SehirID is null
RIGHT JOIN ya da RIGHT OUTER JOIN(ikisi aynı şeyi ifade eder): LEFT OUTER JOIN ile aynı mantıkta çalışır. Bu sefer ikinci tablodaki kayıtların tamamı gelir. İlk tabloda karşılığı olmayan kayıtlar null olarak döner. LEFT OUTER JOIN ile çalıştırdığımız sorguyu RIGHT OUTER JOIN’e çevirerek sorgumuzu tekrar çalıştıralım.
select s.SehirIsmi,my.YiyecekIsmi from Sehirler s RIGHT OUTER JOIN MeshurYiyecekler my ON s.ID=my.SehirID
Aşağıdaki resimde gördüğünüz gibi SehirIsmi null gelen yok. Çünkü MeshurYiyecekler tablosundaki SehirID kolonundaki değerlerin hepsinin karşılığı Sehirler tablosunun ID kolonunda var.
Aşağıdaki script ile MeshurYiyecekler tablosuna bir kayıt ekleyelim. Ve bu kaydın SehirID’sine 16 diyelim. Ekleyeceğimiz kayıt Bursanın İskenderi olacak ama Sehirler kısmına Bursa’yı eklemeyeceğiz.
INSERT INTO [dbo].[MeshurYiyecekler]([ID],[SehirID],[YiyecekIsmi])VALUES (4,16,'İskender')
Insert işlemini yaptıktan sonra RIGHT OUTER JOIN script’imizi tekrar çalıştıralım. Aşağıda gördüğünü gibi İskender değerini görüyoruz. Fakat Sehirler tablosunda İskender ile ilişkilendirilmiş bir sehir olmadığı için SehirIsmi kolonunun null olarak dönüyor.
FULL JOIN ya da FULL OUTER JOIN(ikisi aynı şeyi ifade eder): LEFT OUTER ve RIGHT OUTER JOIN’in birleştirilmiş hali olarak düşünün. İki tablodaki tüm kayıtlar da döner. Fakat karşılığı olmayan kolonlar boş olarak döner.
Aynı script’imizi FULL OUTER JOIN ile çalıştıralım.
select s.SehirIsmi,my.YiyecekIsmi from Sehirler s FULL OUTER JOIN MeshurYiyecekler my ON s.ID=my.SehirID
Aşağıda gördüğünüz gibi,
Sehirler tablosunda kayıtlı olan ama MeshurYiyecekler tablosunda kendisine ait bir meshur yiyeceği girilmemiş olan Gaziantep geldi fakat YiyecekIsmi ise null olarak döndü.
MeshurYiyecekler tablosunda kayıtlı olan ama Sehirler tablosunda kendisine ait bir sehir ismi girilmemiş olan İskender geldi fakat SehirIsmi null olarak döndü.
CROSS JOIN: tabloların kartezyen çarpımını verir. Yani soldaki tablodaki her satıra karşılık olarak sağdaki tablonun tüm satırlarının döndürür. Aşağıdaki şekilde sorgumuzu yazıp sonuca bakarak daha iyi anlayabileceğinizi düşünüyorum.
select s.SehirIsmi,my.YiyecekIsmi from Sehirler s CROSS JOIN MeshurYiyecekler my
Eğer CROSS JOIN’in where koşuluna INNER JOIN’deki ON ifadesine yazdığımız eşitleme işlemini yaparsak INNER JOIN gibi çalışacaktır.
Aşağıdaki script’i çalıştırdığımızda WHERE eklenmiş CROSS JOIN’in INNER JOIN ile aynı sonucu döndürdüğünü göreceksiniz.
select s.SehirIsmi,my.YiyecekIsmi from Sehirler s CROSS JOIN MeshurYiyecekler my where s.ID=my.SehirID
Bu makaleden sonra “SQL Server Execution Plan’daki JOIN Türleri” isimli makalemi okumak isteyebilirsiniz.