SQL Server JOIN Türleri – I (INNER, LEFT, RIGHT, CROSS)

SQL Server, Oracle Add comments

Bu makalede genelde iliÅŸkisel veritabanı [Relational Database] sistemlerinin özelde SQL Server’in temel konularından biri olan JOIN seçeneklerini özetleyeceÄŸiz. SQL Server ne tür JOIN seçenekleri sunuyor, bu seçeneklerin birbirinden farkı nedir, olay sadece syntax farklılığı mıdır, performans cephesinden neler oluyor . . . bu soruları yanıtlayacağız. Table veya view gibi kaynakları birbirine baÄŸlayan JOIN ifadeleri bu kaynaklara uygulanmış SELECT, INSERT…SELECT, SELECT…INTO, UPDATE ve DELETE iÅŸlemlerinde FROM deyimiyle birlikte kullanılır.

Yazının devamına geçmeden önce örnek olarak kullanacağımız tabloları oluşturalım. Örnek bir Öğrenci İşleri projesinde öğrencilerden sorumlu danışman öğrentim üyelerini sakladığımız tablolar yazacağız. Bunun için Ogrenci, Danisman ve bu iki tablo arasındaki ilişkinin tutulduğu OgrenciDanisman tablolarını oluşturacağız.

--Öğrenci tablosu
CREATE TABLE Ogrenci(
	OgrenciId int,
	AdSoyad varchar(100)
)
--Danışman tablosu
CREATE TABLE Danisman(
	DanismanId int,
	AdSoyad varchar(100)
)

--Öğrenci Danışman tablosu
CREATE TABLE OgrenciDanisman(
	OgrenciDanismanId int,
	OgrenciId int,
	DanismanId int
)

--Ogrenci tablosuna kayıt girelim
INSERT Ogrenci VALUES(1,'Öğrenci_1')
INSERT Ogrenci VALUES(2,'Öğrenci_2')
INSERT Ogrenci VALUES(3,'Öğrenci_3')
INSERT Ogrenci VALUES(4,'Öğrenci_4')

--Danışman tablosuna kayıt girelim
INSERT Danisman VALUES(1,'Danışman_1')
INSERT Danisman VALUES(2,'Danışman_2')
INSERT Danisman VALUES(3,'Danışman_3')
INSERT Danisman VALUES(4,'Danışman_4')

--Danışmanı olan öğrenciler için kayıt girelim
--1 nolu öğrencinin danışmanı=2 nolu danışman
INSERT OgrenciDanisman VALUES(1,1,2)
--3 nolu öğrencinin danışmanı=2 nolu danışman
INSERT OgrenciDanisman VALUES(2,3,2)
--4 nolu öğrencinin danışmanı=1 nolu danışman
INSERT OgrenciDanisman VALUES(3,4,1)

Bu tablolardaki veriler aşağıdaki gibi olacaktır;

JOIN yöntemlerini iki veya daha fazla tabloyu aynı anda sorgulamak için tercih ederiz. Sorguda kullanılan tablolar tamamen ayrı tablolar olduğu gibi aynı tablo da olabilir (SELF JOIN). JOIN yazım biçimi genel olarak aşağıdaki gibidir;
FROM ilk_table join_turu ikinci_table [ON (join_kosulu)]
join_turu ifadesi hangi JOIN seçeneğinin (inner, outer veya cross join) kullanılacağını, join_kosulu ise her iki tabloya ait satırların hangi sınırlamayla ilişkilendirileceğini belirtir. Aşağıdaki örnekte FROM bölümünde JOIN yapısı belirtilmiştir.

FROM Ogrenci JOIN OgrenciDanisman
ON (Ogrenci.OgrenciId = OgrenciDanisman.OgrenciId)

Birleştirilen iki tablodan hangisinin baskın olacağı veya hangisinden hangi alanların okunacağı tercih edilien JOIN türüne göre değişkenlik arzeder. Bu amaçla SQL Server aşağıdaki üç temel JOIN türlerini destekler.

  • INNER JOIN (İç BirleÅŸtirici): SQL Server’de varsayılan seçenek olup iki tabloyu JOIN ifadesinde belirtilmiÅŸ olan kolon veya kolonların eÅŸitliÄŸine göre birleÅŸtirir. Bu seçenekte tablolar her iki tarafta ortak olan kolonlar üzerinden birleÅŸtirilir. Tablo arasındaki eÅŸitlik için genellikle = veya <> operatorleri kullanılır. ÖrneÄŸin hem Ogrenci hem de OgrenciDanisman tablosunda olan öğrenci kayıtlarını çekmek için INNER JOIN türü kullanılır. Yani bire bir iliÅŸki için tercih edilir. Yazım biçimi olarak INNER JOIN yazılabileceÄŸi gibi sadece JOIN sözcüğü de yazılabilir.

    Aşağıdaki örnekte danışmanı olan öğrenciler listelenmiştir. JOIN işlemlerinde yazım biçimini daha kısa tutmak ve anlaşılır hale getirmek için tablolar için alias tanımlanır.

    SELECT O.* FROM Ogrenci O
    	INNER JOIN OgrenciDanisman OD
    		ON O.OgrenciId=OD.OgrenciId

    Bu örnekte O.* ifadesiyle Ogrenci tablosundaki tüm alanlar listelenmiştir. Örneğin sadece öğrencinin adını listelemek istemiş olsaydı O.AdSoyad yazmamız yeterli olacaktır. JOIN işlemini 3 tabloya da uygulayabiliriz. Öğrencilerin hangi danışmanlara atandığını listeleyelim. Öğrencinin adı, Ogrenci tablosundan danışmanın adı da Danisman tablosundan alınmıştır.

    SELECT O.OgrenciId,O.AdSoyad,D.DanismanId,D.AdSoyad FROM Ogrenci O
    	INNER JOIN OgrenciDanisman OD
    		ON O.OgrenciId=OD.OgrenciId
    	INNER JOIN Danisman D
    		ON OD.DanismanId=D.DanismanId

  • OUTER JOIN (Dış BirleÅŸtirici): INNER JOIN gibi iki tablo arasında ortak kolonlar üzerinden baÄŸlantı kurar farklı olarak tablolarda karşılığı olmayan satırlar da gelir. İkinci tabloda karşılığı olmayan satırlar NULL olarak döner. Bu JOIN seçeneÄŸini daha çok bir tabloda olup diÄŸer tabloda olmayan kayıtları listelemek için tercih ederiz. OUTER JOIN seçeneÄŸinde hangi tablonun baskın olacağı aÅŸağıdaki ifadelerle belirtilir. Bu JOIN seçeneÄŸinde karşılığı olmayan satırlar WHERE bölümünde ilgili kolonların null deÄŸeriyle karşılaÅŸtırılmasıyla bulunur.
    • LEFT JOIN veya LEFT OUTER JOIN : Bu seçenekte ifadenin solunda ismi yazan tablodaki tüm satırlar listelenir, saÄŸ taraftaki tabloya ait kolonlar ise null olarak döner.

      Aşağıdaki sorguda Ogrenci ve Danisman tabloları arasında LEFT JOIN işlemi uygulanmıştır.

      SELECT * FROM Ogrenci O
      	LEFT JOIN OgrenciDanisman OD
      		ON O.OgrenciId=OD.OgrenciId

      Sonuç listesinde görüldüğü gibi 2 nolu öğrenci herhangi bir danışmana bağlı olmadığı için o satıra karşışık OgrenciDanisman tablosundaki kolonlar null dönmüştür. Bu alanlardan birini filtreleyerek herhangi bir danışmana atanmamış öğrencileri bulabiliriz.

      SELECT * FROM Ogrenci O
      	LEFT JOIN OgrenciDanisman OD
      		ON O.OgrenciId=OD.OgrenciId
      WHERE OD.DanismanId IS NULL

    • RIGHT JOIN veya RIGHT OUTER JOIN : Bu seçenekte ifadenin sağında ismi yazan tablodaki tüm satırlar listelenir, sol taraftaki tabloya ait kolonlar ise null olarak döner.

      Önceki örneğe benzer olarak öğrencisi olmayan danışmanları listeleyebiliriz. Bunun için ilgili tabloları yazdıktan sonra LEFT JOIN yerine RIGHT JOIN ifadesini kullanıp WHERE bölümünü aşağıdaki gibi düzeltmemiz yeterli olacaktır.

      SELECT * FROM OgrenciDanisman OD
      	RIGHT JOIN Danisman D
      		ON D.DanismanId=OD.DanismanId
      WHERE OD.DanismanId IS NULL

    • FULL JOIN veya FULL OUTER JOIN : Bu seçenekte hem saÄŸ hem de soldaki tablonun tüm satırları listelenir. Her iki tabloda da karşılığı olmayan satırlar null olarak döner. AÅŸağıdaki örnekte 3 tabloyu birbiriyle FULL JOIN yaparak Ogrenci ve Danisman tablolarındaki karşılıksız satırları listelemiÅŸ olduk.
      SELECT * FROM Ogrenci O
      	FULL JOIN OgrenciDanisman OD
      		ON O.OgrenciId=OD.OgrenciId
      	FULL JOIN Danisman D ON D.DanismanId=OD.DanismanId

  • CROSS JOIN (Çapraz BirleÅŸtirici): Kartezyen çarpım (cartesian product) olarak ta bilinen bu seçenekte ortak bir alan belirtilmesine gerek kalmadan iki tablo arasında tüm eÅŸleÅŸtirmeleri listeler. Bunu da soldaki tablodaki herbir satıra karşılık saÄŸdaki tablonun tüm satırlarını döndürerek gerçekleÅŸtirir.

    Ogrenci ve Danisman tabloları arasında CROSS JOIN kuralım. Bu durumda her öğrenciye karşılık tüm danışmanlar listelenecektir.

    SELECT * FROM Ogrenci O
    	CROSS JOIN Danisman D
    ORDER BY OgrenciId

Internet’ten alınmış olan aÅŸağıdaki ÅŸekilde JOIN türlerinin anlaşılması açısından kolaylık saÄŸlamaktadır.

JOIN işlemlerinin sadece SELECT tümcesinde değil DELETE, UPDATE ile birlikte de kullanabiliriz. Hatta ciddi bir kolaylık ta sağlayacaktır. Örnek olarak herhangi bir danışmanı olmayan öğrencileri silelim. Öncelikle sonucu getiren SELECT cümlesini yazalım.

SELECT * FROM Ogrenci O
	LEFT JOIN OgrenciDanisman OD
	ON O.OgrenciId=OD.OgrenciId
WHERE OD.DanismanId IS NULL

Bu cümleyi aşağıdaki gibi değiştirmemiz silme işlemi için yeterli olacaktır.

DELETE Ogrenci FROM Ogrenci O
	LEFT JOIN OgrenciDanisman OD
	ON O.OgrenciId=OD.OgrenciId
WHERE OD.DanismanId IS NULL

Yeri gelmişken yazalım. Bu sorguya alternatif olarak aşağıdaki gibi iç içe sorgu yöntemi de kullanılabilir.

DELETE Ogrenci WHERE OgrenciId IN (
	SELECT O.OgrenciId FROM Ogrenci O
		LEFT JOIN OgrenciDanisman OD
		ON O.OgrenciId=OD.OgrenciId
	WHERE OD.DanismanId IS NULL
)

--VEYA
DELETE Ogrenci FROM Ogrenci O WHERE NOT EXISTS (SELECT * FROM OgrenciDanisman WHERE OgrenciId=O.OgrenciId)

--VEYA
DELETE Ogrenci WHERE NOT OgrenciId IN (SELECT OgrenciId FROM OgrenciDanisman)

Tabi bu örnek çok mantıklı olmadığı için performans açısından son 2 alternatifin tercih edilmesi daha doğru olacaktır.

JOIN seçeneklerini SELECT tümcesinde GROUP BY, HAVING, ORDER BY ile birlikte de kullanabiliriz. Aşağıdaki örnekte her danışmanın kaç öğrencisi olduğu sorgulanmıştır.

SELECT
	D.DanismanId,
	MAX(D.AdSoyad)[Danışmanın Adı Soyadı],
	COUNT(OD.OgrenciId) [Öğrenci Sayısı]
FROM OgrenciDanisman OD
	INNER JOIN Danisman D
		ON OD.DanismanId=D.DanismanId
GROUP BY D.DanismanId

Anti Join ve Semi Join

Join işlemleri genellikle iki tablo arasında eşleşen kayıtlar üzerinde birleştirme yapmak için kullanılır. Bazı durumlarda eşleşmeyen yani fark kayıtlar üzerinden de birleştirme yapılabilir. Bunun için Anti Join (Zıt Birleştirme) yöntemi kullanılır. Bu yöntem iki tablo arasındaki zıt kayıtları bulmaktır. Bunun için NOT IN ve NOT EXISTS sözcükleri kullanılır.

ÖrneÄŸin daha önce yaptığımız “danışmanı olmayan öğrenciler” örneÄŸini bu ÅŸekilde yapabiliriz.

SELECT * FROM Ogrenci O
	WHERE NOT EXISTS (SELECT *
				FROM OgrenciDanisman OD
			WHERE O.OgrenciId=OD.OgrenciId)

Bu örnekte iç kısımdaki OgrenciDanisman tablosu ile dış kısımdaki Ogrenci tablosu arasında içermeme iliÅŸkisi kurulmuÅŸtur. İki tablo arasındaki fark alınmıştır. Bu amaçla Oracle’de MINUS sözcüğü bulunur. SQL Server’de bu sözüğü karşılık ve içermeme iliÅŸkisi için EXCEPT ifadesi kullanılabilir.

SELECT OgrenciId FROM Ogrenci
EXCEPT
SELECT OgrenciId FROM OgrenciDanisman

Daha çok iki farklı veri setini birleştirme için kullanılan bakat bu sözüğün en büyük dezavantajı UNION ve INTERSECT sözcükleri gibi üst ve alt kayıt seti arasında doğrudan bir ilişki kuramaması ve her iki tarafta da kayıt kolon sayılarının eşit olmasını zorunlu kılmasıdır. Örneğin burada sözkonusu öğrencinin adını almak için ayrıca bir içiçe sorgu yazmak gerekiyor.

Konuyla ilgili bahsedeceğimiz diğer JOIN türü Zıt Birleştirmenin tersi olarak algılayabileceğimiz Semi-Join diye bilinen yarı birleştirme işlemidir. Burada IN ve EXISTS kullanılmaktadır. Önceki örneğin tersi olarak danışmanı olan öğrencileri listeleyelim.

SELECT * FROM Ogrenci O
	WHERE EXISTS (SELECT *
				FROM OgrenciDanisman OD
			WHERE O.OgrenciId=OD.OgrenciId)

Leave a Reply


3 × 2 =

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS GiriÅŸ