Bu bölümde, SQL Server’da join (birleştirme) işleminin temellerini öğreneceğiz. Bir T-SQL SELECT ifadesindeki FROM yan tümcesinin, sorgunun sonraki aşamalarında kullanılacak ara sanal tabloları nasıl oluşturduğunu keşfedeceğiz. İki tablodaki satırların kombinasyonlarının kartezyen ürün verdiğini göreceğiz. Ayrıca bu ve sonraki bölümlerde çok tablolu T-SQL sorgularında kullanılan genel join türlerini de göreceğiz.

FROM İfadesi ve Sanal Tablolar

SQL Server’da bir sorgudaki işlemlerin mantıksal sırasını zaten öğrenmiştik. SELECT ifadesindeki FROM deyiminin mantıksal işlem sırasındaki ilk aşama olduğunu hatırlıyorsunuzdur. FROM ile hangi tablo veya tabloların sorguda kullanılacağı belirleniyordu. Bu ve sonraki bölümlerde göreceğiniz gibi, sorgu kaynağı olarak tek bir tabloyu veya birden fazla tabloyu bir araya getirip kullanacağız. FROM ifadesinin diğer yeteneklerini de görebilmek için ifadenin işlevini, bir sanal tablo oluşturma ve bu tabloyu doldurması olarak düşünebilirsiniz. Bu sanal tablo FROM ifadesinin çıktısını taşıyacak ve daha sonra SELECT ifadesinin diğer aşamaları (WHERE ifadesi gibi) tarafından kullanılacaktır. Bir FROM ifadesini, join operatörleri gibi ekstra işlevler ekleyerek kullanıldığında, FROM öğelerinin amacının sanal tabloya satır eklemek veya tablodan satır silmek olduğunun anlaşılması açısından faydalı olacaktır.

Bir FROM deyimi tarafından oluşturulan sanal tablo yalnızca mantıksal bir objedir. SQL Server’da, FROM ifadesinin sonuçları, WHERE ifadesine ya da diğer sonraki aşamalara geçirildiği için kalıcı ya da geçici olsun, hiçbir fiziksel tablo oluşturulmaz.

Bu kursta daha önce yapılan sorgulamalar için kullandığınız SELECT ifadesinin syntax’ının aşağıdaki gibi olduğunu görmüştük:

SELECT ...
FROM <tablo> AS <takma adı>;

İlk önce FROM ifadesi işlenir, bunun sonucunda da oluşturulan tüm tablo takma adları SELECT ifadesinde kullanılabilir. Ayrıca örneklerde birçok takma adı örneği göreceğiz. Takma ad kullanımı isteğe bağlı olsa da sorgularınızı yazarken (self join sorguları dışında) ne kadar kullanışlı bir araç olduğunu hemen göreceksiniz. Aynı çıktıya sahip ancak takma ad kullanımlarında farklı olan aşağıdaki iki sorguyu karşılaştırın.

İlk sorguda takma adı kullanılmamıştır:

USE TSQL ;
GO
SELECT Sales.Orders.orderid, Sales.Orders.orderdate,
Sales.OrderDetails.productid,Sales.OrderDetails.unitprice,
Sales.OrderDetails.qty
FROM Sales.Orders
JOIN Sales.OrderDetails ON Sales.Orders.orderid = Sales.OrderDetails.orderid;

İkinci örnekte aynı veriler çekilmektedir fakat aynı zamanda tablo takma adı da kullanılmıştır:

USE TSQL ;
GO
SELECT o.orderid, o.orderdate,
od.productid, od.unitprice,
od.qty
FROM Sales.Orders AS o
JOIN Sales.OrderDetails AS od ON o.orderid = od.orderid;

Görüldüğü üzere tablo takma adları, performansı etkilemeden sorgunun okunabilirliğini artırmaktadır. Çok değişkenli sorgularınızda tablo takma adları kullanmanız şiddetle tavsiye edilir.

Bir tablo, FROM ifadesinde bir takma adıyla belirtildikten sonra, diğer ifadeler içerisinde bu tablodaki sütunlara başvururken verilen takma adı kullanmak en iyi yöntemdir.

JOIN Terminolojisi: Kartezyen Ürün

T-SQL’de çok değişkenli sorgular yazmayı öğrenirken Kartezyen ürün kavramını anlamak önemlidir. Kartezyen ürün, matematikte iki kümenin ürünü olarak karşımıza çıkar. İki ögeden oluşan bir küme ve altı ögeden oluşan başka bir kümenin Kartezyen ürünü, 12 ögeden (6×2) oluşan bir gruptur. Veri tabanlarında ise Kartezyen ürün, bir tablonun her satırının başka bir tablonun tüm satırlarına birleştirilmesinin sonucudur. 10 satırlık bir tablo ve 100 satırlık başka bir tablonun Kartezyen ürünü 1.000 satırlık bir sonuçtur. Çoğu T-SQL sorgusunda Kartezyen ürün istenen sonuç değildir. Tipik olarak bir Kartezyen ürün, aralarında herhangi bir mantıksal ilişki göz önüne alınmadan iki tablo birleştirildiğinde ortaya çıkar. SQL Server sorgu işlemcisi, tablolar arasındaki ilişkiler hakkında hiçbir bilgi olmadan olası tüm satır kombinasyonlarını çıkartır. Bir sayı tablosu veya test verileri oluşturmak gibi bazı pratik uygulamalara sahip olsa da tipik olarak kullanışlı değildir ve performansa ciddi etkileri olabilir. Sonraki bölümde Kartezyen birleşimlerinin bir uygulamasını öğreneceksiniz.

Bir sonraki yazıda, bir birleşim işleminin syntax’ını belirlemek için iki farklı yöntemi karşılaştıracağız. Bir yöntemin sizi yanlışlıkla Kartezyen ürün sorguları yazmaya yönlendirdiğini göreceksiniz.

JOIN Türlerine Genel Bakış

SQL Server, FROM ifadesi tarafından üretilen sanal tabloyu SELECT ifadesinde doldurmak için JOIN ifadelerini kullanır. Bunlar SELECT ifadesindeki sanal tabloya, sonraki mantıksal aşamalara geçilmeden önce satır ekleme veya kaldırma işlemi yaparlar:

  • Çapraz birleştirme işleci (CROSS JOIN), iki tablonun satırlarının olası tüm kombinasyonlarını sanal tabloya ekler. Satırların filtrelenmesi, WHERE ifadesiyle olur. Çoğu sorguda bu operatörü kullanmaktan kaçınılmalıdır.
  • İç birleştirme operatörü (INNER JOIN (ya da sadece JOIN)) önce bir Kartezyen ürün oluşturur ve ardından ON fonksiyonunda verilen predicate’i kullanarak sanal tabloda bu predicate’i karşılamayan tüm satırları kaldırır ve sonuçları gösterir. INNER JOIN, müşterilerin ID numarası gibi karşılıklı tablolarda eşleşen özelliklere sahip satırları çeken çok yaygın bir birleşim işlemidir.
  • Dış birleştirme operatörü (LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN) önce bir Kartezyen ürün oluşturur ve aynı INNER JOIN’de olduğu gibi her tabloda eşleşen satırları bulmak için sonuçları filtreler. Ancak bir tablodaki tüm satırlar korunur ve ilk filtre uygulandıktan sonra sanal tabloya geri eklenir. Eşleşen değerlerin bulunmadığı niteliklere NULL yerleştirilir.

Not: CROSS veya OUTER ile belirtilmediği sürece, JOIN ifadesinin varsayılan işlevi INNER birleşimidir.

T-SQL Syntax Seçenekleri

SQL Server, tarihi boyunca, SQL dili için Amerikan Ulusal Standartlar Enstitüsü (ANSI) standartlarındaki değişikliklere ayak uydurmak üzere değişime uğramıştır. Bu değişikliklerin göründüğü en dikkat çekici yerlerden biri, FROM deyimindeki JOIN ifadesinin syntax’ıdır. ANSI SQL-89’da hiçbir ON operatörü tanımlanmamıştı. JOIN işlemleri, tabloların virgülle ayrılmış şekli olarak temsil edilmiş ve INNER JOIN gibi bir filtreleme de WHERE deyiminde gerçekleştiriliyordu. Bu syntax hâlâ SQL Server tarafından desteklenmektedir fakat WHERE deyiminde OUTER JOIN işlevinin filtresininin yazılması zor olması nedeniyle, diğer filtrelemelere ek olarak, bu syntax önerilmemektedir. Ayrıca bir WHERE deyimi yanlışlıkla atlanırsa, ANSI SQL-89 stilindeki join işlemleri, kolaylıkla Kartezyen ürünleri haline gelebilir ve performans sorunlarına neden olabilir.

Aşağıdaki sorgular bu syntax’ı ve çıkacak olası sorunu göstermektedir:

USE TSQL;
GO
/* 
Bu sentaks, WHERE ifadesinde filtreleme işlemi gerçekleştiren inner join ANSI SQL-89 sentaksıdır.
*/
SELECT c.companyname, o.orderdate
FROM Sales.Customers AS c, Sales.Orders AS o
WHERE c.custid = o.custid;
....
(830 row(s) affected)
/*
Bu sentaks, WHERE ifadesini atlayarak yanlışlıkla Kartezyen birleşime neden olan bir ANSI SQL-89 inner join sentaksıdır.
*/
SELECT c.companyname, o.orderdate
FROM Sales.Customers AS c, Sales.Orders AS o;
...
(75530 row(s) affected)

ANSI SQL-92 standardının ortaya çıkmasıyla birlikte ON ifadesi için destek eklendi. T-SQL ayrıca bu syntax’ı da desteklemektedir. Join işlemleri, FROM deyiminde belirtilen uygun JOIN operatörü kullanılarak temsil edilmektedir. Bu sayede bir filtre belirleyicisi haline gelen tablolar arasındaki mantıksal ilişki de ON ifadesiyle temsil edilmektedir.

Aşağıdaki örnek, bir önceki sorgunun yeni syntax ile yazılmış versiyonudur:

SELECT c.companyname, o.orderdate
FROM Sales.Customers AS c JOIN Sales.Orders AS o
ON c.custid = o.custid;

Not: ANSI SQL-92 sözdizimi, Kartezyen bağlarının yanlışlıkla oluşturulmasını zorlaştırır. JOIN kullanırken ON ifadesi eksikse syntax hatası ortaya çıkacaktır.