SQL Server’da iki kümeyi birleştirme ve karşılaştırma için alternatif yöntemler sunmaktadır. Bu bölümde SQL Server 2005 ile gelen APPLY operatörünü öğreneceğiz.

APPLY Operatörü Kullanımı

APPLY operatörü kullanarak bir sorguda dıştaki tablodan dönen her satır için bir tablo ifadesi çağrılır. APPLY bir set operatörü değil bir tablo operatörüdür. JOIN’de olduğu gibi FROM ifadesinde kullanarak birbiriyle uyumlu iki tablo üzerinde işlem yapılabilir.

Kavramsal olarak bir tablodaki her satır için bir tablo ifadesi (TVF gibi) çağrıldığı için bu yönüyle ilişkili alt sorgulara benzer ancak skaler veya multi-valued değer döndürdüğü için bu yönüyle farklıdır. Mesela kullanılan tablo ifadesi TVF olsun; tablodan dönen satırlar TVF’e input olarak verilebilir.

Not: APPLY ile kullanılacak tabloların sırası left ve right terimleriyle belirtilirken bu terimler aynı JOIN ifadesindeki gibi kullanılır.

FROM ifadesinde APPLY operatörü kullanırken iki input da kümesi de yazılır. APPLY operatörü kullanıldığında set operatörlerinden farklı olarak verilen ilk tablodaki her satıra karşılık ikinci tablo işlenir.

APPLY operatörünün CROSS APPLY ve OUTER APPLY şeklinde iki formu bulunmaktadır. APPLY operatörünün genel syntax aşağıdaki gibidir. Sol tablodan alınan her sonuç sağ tabloya input olarak geçirilir:

SELECT <column_list>
FROM <left_table_source> AS <alias>
[CROSS]|[OUTER] APPLY
 <right_table_source> AS <alias>; 

CROSS APPLY Operatörü

Bir önceki başlıkta belirtildiği üzere, APPLY sol tablodaki satırların her biri için sağdaki tabloyu yürütür ve sonuçları tek bir sonuç kümesi olarak döndürür.

Operatörün CROSS APPLY formu, çıktı sonucunu yalnızca sol tablodaki değerlerden sağ tablo kaynağında bulunduğunda ayarlar.

Not: CROSS APPLY’daki CROSS terimi, CROSS JOIN’deki CROSS ile aynı anlamda değildir. CROSS JOIN’de sol ve sağ tablodaki satırların tüm kombinasyonları döndürülürken, CROSS APPLY’da sonuç sol tablo kaynağındaki değerlerden sağ tabloda bulunduğu şekline göre ayarlanır.

CROSS APPLY ifadesi INNER JOIN’e çok benzerdir. INNER JOIN kullanılan çoğu T-SQL ifadesi CROSS APPLY kullanılarak yeniden yazılabilir.

Aşağıdaki TSQL veri tabanı kullanılan örnekte Sipariş ve siparişi ayrıntısı tabloları arasında INNER JOIN kullanarak basit bir SELECT ifadesi yazılmıştır:

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

Dönen sonuç:

orderid orderdate productid unitprice qty
----------- ----------------------- ----------- --------------------- ------
10248 2006-07-04 00:00:00.000 11 14.00 12
10248 2006-07-04 00:00:00.000 42 9.80 10
10248 2006-07-04 00:00:00.000 72 34.80 5
10249 2006-07-05 00:00:00.000 14 18.60 9
10249 2006-07-05 00:00:00.000 51 42.40 40
10250 2006-07-08 00:00:00.000 41 7.70 10
10250 2006-07-08 00:00:00.000 51 42.40 35
10250 2006-07-08 00:00:00.000 65 16.80 15
...
(2155 row(s) affected) 

Aynı sorgu CROSS APPLY kullanılarak yeniden yazılabilir:

SELECT o.orderid, o.orderdate,
od.productid, od.unitprice, od.qty
FROM Sales.Orders AS o
CROSS APPLY ( SELECT productid, unitprice, qty
 FROM Sales.OrderDetails AS so
 WHERE so.orderid = o.orderid
 ) AS od; 

Not: JOIN ifadesindeki Sales.OrderDetails.orderid = Sales.Orders.orderid şartı, sorgu CROSS APPLY kullanarak yeniden yazıldığında, sağdaki tablo INNER JOIN’den WHERE ifadesine geçmiştir.

Sorgu yürütüldüğünde INNER JOIN ile yazılan sorguyla aynı sonucu döndürecektir:

orderid orderdate productid unitprice qty
----------- ----------------------- ----------- --------------------- ------
10248 2006-07-04 00:00:00.000 11 14.00 12
10248 2006-07-04 00:00:00.000 42 9.80 10
10248 2006-07-04 00:00:00.000 72 34.80 5
10249 2006-07-05 00:00:00.000 14 18.60 9
10249 2006-07-05 00:00:00.000 51 42.40 40
10250 2006-07-08 00:00:00.000 41 7.70 10
10250 2006-07-08 00:00:00.000 51 42.40 35
10250 2006-07-08 00:00:00.000 65 16.80 15
...
(2155 row(s) affected) 

OUTER APPLY Operatörü

Operatörün OUTER APPLY formu kullanıldığında, output kümesinde sol tablodaki tüm satırlar ve bu satırların karşılık geldiği sağ tablodaki tüm satırlar bulunur. Sağ tablonun sol tablodan bir değer içermemesi durumunda, sağ tablodan gelen sütunlar NULL değerli olacaktır.

Bu durum OUTER APPLY ifadesini bir LEFT OUTER JOIN ifadesine çok benzer kılmaktadır. LEFT OUTER JOIN içeren çoğu T-SQL ifadesi, OUTER APPLY kullanılarak yeniden yazılabilir.

Tabloların sırası sonucu etkileyebilir.

Aşağıdaki SELECT ifadesinde LEFT OUTER JOIN kullanarak Customers ve Suppliers tablolarından müşteri ve tedarikçilerin ülkelerine sorgu atılmıştır:

SELECT DISTINCT s.country AS supplier_country, c.country as customer_country
FROM Production.Suppliers AS s
LEFT OUTER JOIN Sales.Customers AS c
ON c.country = s.country
ORDER BY supplier_country; 

Not: Sorgu OUTER APPLY kullanarak yeniden yazıldığında Sales.Customers.Country = Production.Suppliers.Country şartı, LEFT OUTER JOIN’den sağ tablonun WHERE ifadesine geçmiştir.

Bu sorgu, LEFT OUTER JOIN kullanılan sorguyla aynı sonucu döndürür:

supplier_country customer_country
---------------- ----------------
Australia NULL
Brazil Brazil
Canada Canada
Denmark Denmark
Finland Finland
France France
Germany Germany
Italy Italy
Japan NULL
Netherlands NULL
Norway Norway
Singapore NULL
Spain Spain
Sweden Sweden
UK UK
USA USA 
 (16 row(s) affected) 

Sorgu OUTER APPLY kullanılarak yeniden yazılabilir:

SELECT DISTINCT s.country AS supplier_country, c.country as customer_country
FROM Production.Suppliers AS s
OUTER APPLY ( SELECT country
 FROM Sales.Customers AS cu
 WHERE cu.country = s.country
 ) AS c
ORDER BY supplier_country; 

Dönen sonuç:

supplier_country customer_country
---------------- ----------------
Australia NULL
Brazil Brazil
Canada Canada
Denmark Denmark
Finland Finland
France France
Germany Germany
Italy Italy
Japan NULL
Netherlands NULL
Norway Norway
Singapore NULL
Spain Spain
Sweden Sweden
UK UK
USA USA
 (16 row(s) affected) 

CROSS APPLY ve OUTER APPLY Özellikleri

Belirttiğimiz gibi CROSS APPLY ve INNER JOIN ifadeleri arasında ve bir de OUTER APPLY ve LEFT OUTER JOIN ifadeleri arasında çok benzerlik vardır.

Ancak, APPLY operatörleri JOIN kullanılarak yazılamayan bazı sorgu türlerinin çalıştırılabilmesini sağlar. Bu sorgu türleri, sağ tabloda işlem yapmadan önce sol tabloda işlem gerçekleştiren sorgulardır. Gösterdiğimiz iki örnek sorgu da sağ tablo kaynağı olarak TVF kullanmaktır.

Aşağıdaki sorguda hiç sipariş vermemiş müşteriler de dahil edilerek her müşterinin verdiği en son üç sipariş için sorgu atılmıştır:

SELECT C.custid, TopOrders.orderid, TopOrders.orderdate
FROM Sales.Customers AS C
OUTER APPLY
 (SELECT TOP (3) orderid, CAST(orderdate AS date) AS orderdate
 FROM Sales.Orders AS O
 WHERE O.custid = C.custid
 ORDER BY orderdate DESC, orderid DESC) AS TopOrders; 

Not: Burada OUTER APPLY kullanıldığından hiç sipariş vermeyen müşteri kayıtları da sonuca dahil edilmiştir, orderid ve orderdate sütunlarında NULL değerlerin olduğunu görebilirsiniz. OUTER APPLY yerine CROSS APPLY kullanılsaydı, bu kayıtlar dahil edilmeyecekti.

Aşağıda NULL içeren satırlar da dahil olmak üzere sonuçlar gösterilmiştir:

custid orderid orderdate
----------- ----------- ----------
1 11011 2008-04-09
1 10952 2008-03-16
1 10835 2008-01-15
2 10926 2008-03-04
2 10759 2007-11-28
2 10625 2007-08-08
22 NULL NULL
57 NULL NULL
58 11073 2008-05-05
58 10995 2008-04-02
58 10502 2007-04-10
(265 row(s) affected) 

APPLY operatörünün kullanıldığı yerde tablo kaynağı olarak TVF kullanımı önerilmektedir.

Aşağıdaki örnekte, dbo.fn_TopProductsByShipper adlı TVF’ye input olarak sol tablodaki supplierid sütunu kullanılmıştır. Suppliers tablosunda karşılığı olmayan satırlar görüntülenmez:

SELECT S.supplierid, s.companyname, P.productid, P.productname, P.unitprice
FROM Production.Suppliers AS S
CROSS APPLY dbo.fn_TopProductsByShipper(S.supplierid) AS P; 

Dönen sonuç:

supplierid companyname productid productname unitprice
----------- -------------- ----------- ------------- ---------
1 Supplier SWRXU 2 Product RECZE 19.00
1 Supplier SWRXU 1 Product HHYDP 18.00
1 Supplier SWRXU 3 Product IMEHJ 10.00
2 Supplier VHQZD 4 Product KSBRM 22.00
2 Supplier VHQZD 5 Product EPEIM 21.35
2 Supplier VHQZD 65 Product XYWBZ 21.05
3 Supplier STUAZ 8 Product WVJFP 40.00
3 Supplier STUAZ 7 Product HMLNI 30.00
3 Supplier STUAZ 6 Product VAIIV 25.00 

Kaynak:
FROM (Transact-SQL)
Using APPLY