CROSS APPLY ve OUTER APPLY Nasıl Çalışır? Örneklerle SQL Server APPLY Operatörü
Beceri rehberi

CROSS APPLY ve OUTER APPLY Nasıl Çalışır? Örneklerle SQL Server APPLY Operatörü

Hazırlayan: Mindset Institute EditörlüğüGüncellendi: 6 dk okuma

APPLY, soldaki tablonun her satırı için sağdaki ifadeyi ayrı ayrı çalıştırır. Böylece satıra bağlı bir fonksiyon, alt sorgu ya da JSON dizisi sonucunu tek sorguda satırlarla birleştirirsiniz.

Bir bakışta

  1. APPLY, sağ tarafı sol satır başına çalıştırır. JOIN iki bağımsız kaynağı koşulla eşleştirir; APPLY ise sağ tarafın sol satırdaki değeri argüman olarak kullanmasına izin verir.
  2. CROSS APPLY boş sonucu eler, OUTER APPLY korur. Aradaki ilişki INNER JOIN ile LEFT JOIN arasındaki ilişkiye benzer.
  3. En güçlü olduğu yer tablo değerli fonksiyonlar ve satıra bağlı alt sorgulardır. Hesaplanan değeri bir kez yazıp yeniden kullanmak ve JSON dizisini satırlara açmak da yaygın kullanımlardır.
  4. Bedeli sol satır sayısıyla artabilir. Sağ taraf her sol satır için değerlendirilir; yürütme planına bakmadan JOIN'den hızlı ya da yavaş demeyin.

APPLY ne yapar ve JOIN'den nasıl ayrılır?

JOIN, iki tablo kaynağını bir koşulla eşleştirir. İki taraf da birbirinden bağımsız hazırdır; sol taraftaki bir değeri sağ tarafın içine argüman olarak veremezsiniz. APPLY bu noktada farklıdır: sağdaki tablo ifadesi soldaki tablonun her satırı için ayrı ayrı değerlendirilir ve o satırın sütunlarını kullanabilir.

Microsoft belgesi mantığı şöyle anlatır: sağ kaynak yaklaşık olarak TVF(sol_satır) biçiminde düşünülür; burada TVF, sol satırdan değer alan bir tablo değerli fonksiyondur. Her sol satır için üretilen küçük sonuç kümeleri birleştirilir ve çıktıda soldaki satırın sütunları, sağdaki ifadenin sütunlarıyla yan yana gelir. Yön de önemlidir: sağ taraf soldaki sütunlara başvurabilir, ama sol taraf sağdaki sütunlara başvuramaz.

Bu yapı birkaç ihtiyacı kolaylaştırır: satır başına sonuç döndüren bir fonksiyonu çağırmak, her satır için sınırlı sayıda ilgili kaydı almak ve bir sütunda saklanan diziyi satırlara açmak. Düz JOIN ile bunları yazmak ya mümkün olmaz ya da pencere fonksiyonu gibi başka bir araca yönelmeyi gerektirir.

CROSS APPLY ve OUTER APPLY: sağ taraf boş dönerse ne olur?

APPLY yazarken CROSS ya da OUTER seçmek zorundasınız. Fark yalnızca sağdaki ifadenin belirli bir sol satır için boş sonuç döndürdüğü durumda ortaya çıkar.

CROSS APPLY'da sağ taraf boş dönen sol satır sonuçtan düşer. Davranış INNER JOIN'e benzer: eşleşme yoksa satır yoktur. OUTER APPLY'da ise sol satır korunur ve sağ tarafın sütunları NULL olarak gelir; davranış LEFT JOIN'e benzer. Belge bunu şöyle özetler: OUTER seçildiğinde sağ taraf boş dönse bile sol tablonun her satırı için bir satır üretilir.

Pratik kural: sol taraftaki hiçbir kaydı kaybetmek istemiyorsanız OUTER APPLY, yalnızca sağ tarafta karşılığı olanlarla ilgileniyorsanız CROSS APPLY kullanın. Örneğin hiç siparişi olmayan müşterileri de raporda görmek istiyorsanız OUTER APPLY, yalnızca sipariş vermiş müşterilerle çalışıyorsanız CROSS APPLY uygundur.

Şekil 1

Fark, sağ tarafın boş döndüğü satırlarda ortaya çıkar

Sol satırın akıbeti ve JOIN karşılığı

CROSS APPLYOUTER APPLY
Sağ taraf boş dönerseSol satır sonuçtan düşerSol satır korunur
Sağ sütunların değeriHer zaman doluBoş eşleşmede NULL
JOIN'deki karşılığıINNER JOIN davranışıLEFT JOIN davranışı
Ne zaman seçilirYalnızca karşılığı olanlar gerekirseSol taraftan kayıp istenmiyorsa
Kaynak: Kaynak: Microsoft Learn, FROM yan tümcesi (APPLY)Mindset Institute

Örnek: satıra bağlı alt sorgu

Müşteri ve sipariş tabloları olsun. Her müşteri için en son siparişleri listelemek istiyorsunuz. Alt sorgunun müşteri numarasına bağlı olması gerekir; bu yüzden onu FROM bölümüne APPLY ile yazarsınız:

SELECT m.customer_name, s.siparis_no, s.siparis_tarihi FROM customer AS m CROSS APPLY ( SELECT TOP (@adet) siparis_no, siparis_tarihi FROM siparis WHERE siparis.customer_id = m.customer_id ORDER BY siparis_tarihi DESC ) AS s;

Parantez içindeki alt sorgu, dıştaki m.customer_id değerine başvurur ve her müşteri için ayrı çalışır. @adet değişkeni kaç kaydın isteneceğini taşır. TOP ile ORDER BY birlikte yazılmazsa hangi kayıtların döneceği belirsizdir; 'en son' ifadesini sıralama tanımlar.

CROSS APPLY'ı OUTER APPLY ile değiştirirseniz hiç siparişi olmayan müşteriler de listede kalır ve siparis_no ile siparis_tarihi sütunları NULL gelir. Grup başına ilk kayıt problemine pencere fonksiyonuyla yaklaşan alternatif çözümler ayrı bir rehberde ele alınır; APPLY'ın avantajı, sıralama ve sınırlamayı doğrudan alt sorgunun içinde ifade etmenizdir.

Tablo değerli fonksiyonla kullanım

APPLY'ın asıl tasarım amacı, sol satırdan değer alan bir tablo değerli fonksiyonu çağırmaktır. Satır içi bir fonksiyon tanımlayıp her müşteriye uygulayabilirsiniz:

CREATE FUNCTION dbo.customer_orders (@customer_id INT) RETURNS TABLE AS RETURN ( SELECT siparis_no, tutar FROM siparis WHERE customer_id = @customer_id );

SELECT m.customer_name, f.siparis_no, f.tutar FROM customer AS m CROSS APPLY dbo.customer_orders(m.customer_id) AS f;

Fonksiyonun argümanı sol tablonun sütunudur; JOIN ile bu çağrıyı yazmak mümkün değildir. Belge, tablo değerli fonksiyon ya da türetilmiş tablo kullanıldığında sonuna takma ad yazılmasının gerekli olduğunu belirtir; bu örnekte f takma adı o işi görür.

Sistem tarafında da sık görülür. Belgedeki örneklerden biri, plan önbelleğindeki sorguların plan tanıtıcılarını bir sistem fonksiyonuna CROSS APPLY ile geçirerek her sorgunun yürütme planını listeler. Yani APPLY yalnızca uygulama verisinde değil, yönetim ve izleme sorgularında da kullanılır.

Hesaplanan değeri bir kez yazıp yeniden kullanmak

SQL'de SELECT listesinde tanımladığınız takma adı aynı SELECT'in içinde başka bir ifadede kullanamazsınız. Karmaşık bir hesabı birkaç yerde tekrar yazmak yerine, hesabı APPLY ile küçük bir türetilmiş tabloya taşıyabilirsiniz:

SELECT s.siparis_no, h.vergi, h.net FROM siparis AS s CROSS APPLY ( SELECT s.tutar * s.kdv_orani AS vergi, s.tutar - s.indirim AS net ) AS h WHERE h.net > 0;

Bu alt sorgu FROM bölümü olmadan yalnızca ifadelerden oluşur ve her siparişten tek satır üretir; dolayısıyla satır kaybı olmaz. Hesaplanan sütunlara h.vergi ve h.net olarak hem SELECT'te hem WHERE'de başvurabilirsiniz. Böylece aynı formülü iki yerde yazıp birini güncellemeyi unutma riski azalır.

Bu kalıp özellikle uzun CASE ifadeleri, tarih hesapları ve metin ayrıştırma adımları için işe yarar. Hesap her satır için bir kez yapılır ve sorgunun geri kalanı yalnızca takma adlara bakar.

Dizi ve JSON açmak: OPENJSON ile APPLY

Bir sütunda dizi biçiminde JSON saklıyorsanız, her kayıt için bu diziyi satırlara açmak gerekir. Microsoft belgesi bu durumu açıkça anar: bireysel alanlarda saklanan JSON dizilerini açıp ana satırlarla eşleştirmek için tipik olarak CROSS APPLY kullanılır.

SELECT s.siparis_no, e.value AS neden FROM siparis AS s CROSS APPLY OPENJSON(s.nedenler) AS e;

OPENJSON sol satırdaki nedenler sütununu okur ve dizinin her elemanını bir satır olarak döndürür. Böylece 'tek sütunda çok değer' yapısı, ayrı bir alt tabloymuş gibi sorgulanır. OPENJSON, JSON_VALUE ve FOR JSON işlevlerinin ayrıntıları SQL Server'da JSON sorgulama rehberinde ele alınır.

Her kaydın dizisi boş olabiliyorsa hangi APPLY'ın seçildiği önem kazanır: CROSS APPLY dizisi boş olan kayıtları sonuçtan çıkarır, OUTER APPLY korur. Raporda tüm siparişleri görmek istiyorsanız, dizinin boş olabileceğini düşünerek OUTER APPLY'a geçin ve sonucu gerçek veriyle sınayın.

Sık hatalar ve performans notları

  • OUTER APPLY yazıp ardından WHERE ile sağ taraftaki bir sütunu filtrelemek. NULL gelen satırlar filtreye takılır ve sonuç fiilen CROSS APPLY gibi davranır. Koşul sağ taraf için geçerliyse alt sorgunun içine yazın.
  • Alt sorguda TOP kullanıp ORDER BY unutmak. Hangi kayıtların döneceği belirsiz olur.
  • Takma adı unutmak. Türetilmiş tablo ve tablo değerli fonksiyon APPLY sağ tarafında takma ad ister.
  • Beklenenden fazla satır görmek. Sağ taraf her sol satır için birden çok satır döndürebilir; bu çoğalma APPLY'ın doğası gereğidir, hata değildir.
  • Her durumda APPLY'ın JOIN'den hızlı olduğunu varsaymak. Sağ taraf her sol satır için değerlendirildiğinden, sol tablo büyükse ve sağ ifade pahalıysa maliyet artar.

Performans için ilişki sütununa indeks koyun ve yürütme planında APPLY'ın altındaki işlemin kaç kez çalıştığına bakın. Aynı sonucu JOIN ile üretebiliyorsanız iki yazımı da ölçüp karşılaştırın; genel bir hüküm yerine kendi veriniz üzerindeki plan belirleyici olsun. Ölçüm yöntemi için yavaş sorguları hızlandırma rehberine bakabilirsiniz.

Taşınabilirlik de akılda tutulmalıdır: APPLY, SQL Server ailesinin kullandığı T-SQL'e ait bir söz dizimidir. Başka bir veritabanı sisteminde benzer işlev farklı bir adla bulunabilir; geçiş yaparken o sistemin kendi belgesine bakın.

Bu beceriyi Mindset programlarında nerede çalışırsınız?

APPLY, JOIN mantığının ve satıra bağlı alt sorgunun üzerine oturur. SQL ile Programlama Eğitimi, tabloları birleştirme ve Inner, Cross, Full Outer ve Self Join konularını ayrı derslerde işler; bu, APPLY'a geçmeden önce sağlam olması gereken zemindir.

SQL ile Veri Sorgulama (İleri) programı ise alt sorgular ve korelasyon teknikleri, görünümler ile stored procedure ve pencere fonksiyonları gibi modüllerle APPLY'ın yanında kullanılan araçları kapsar. Veri analisti ya da raporlama geliştiricisi olarak satır başına hesap yapan sorgular yazıyorsanız bu iki program sorgu repertuvarınızı tamamlar. Kapsam ayrıntısı program sayfalarında yer alır.

İlgili Mindset programı

SQL ile Programlama Eğitimi

Sık sorulanlar

Sık sorulan sorular

CROSS APPLY ile INNER JOIN aynı şey midir?

Boş sonuç davranışı açısından benzerler: eşleşmeyen satır düşer. Ancak INNER JOIN iki bağımsız kaynağı bir koşulla eşleştirir, CROSS APPLY ise sağ ifadeyi her sol satır için çalıştırır ve sol satırın değerini ona verebilir. Bu yüzden tablo değerli fonksiyonla ya da satıra bağlı alt sorguyla çalışırken INNER JOIN yetersiz kalır, CROSS APPLY gerekir.

OUTER APPLY ne zaman kullanılır?

Sağ tarafta karşılığı olmayan sol satırların da sonuçta görünmesi gerektiğinde. Örneğin hiç siparişi olmayan müşteriyi raporda tutmak, boş dizili kaydı kaybetmemek ya da fonksiyonun boş döndüğü satırı yine de listelemek istediğinizde OUTER APPLY seçilir. Sağ sütunlar bu satırlarda NULL gelir.

APPLY kullanmak için tablo değerli fonksiyon yazmam şart mı?

Hayır. Sağ tarafa parantez içinde bir alt sorgu, hatta yalnızca ifadelerden oluşan küçük bir SELECT yazabilirsiniz. Fonksiyon, aynı mantığı birçok sorguda yeniden kullanmak istediğinizde anlamlıdır. Tek seferlik işlerde satır içi alt sorgu daha okunaklıdır ve takma adı unutmamak yeterlidir.

APPLY yavaş çalışıyorsa nereye bakmalıyım?

Önce yürütme planında APPLY'ın altındaki işlemin kaç kez çalıştığına ve hangi erişim yöntemini kullandığına bakın. Alt sorgunun ilişki sütunu (örneğin müşteri numarası) için indeks yoksa her sol satırda tablo taranıyor olabilir. İndeks ekleyin, gereksiz sütunları çıkarın ve aynı sonucu veren JOIN ya da pencere fonksiyonu yazımıyla karşılaştırın.

Başka veritabanlarında APPLY var mı?

APPLY, T-SQL'in söz dizimidir ve SQL Server ile Azure SQL ürünlerinde bulunur. Başka sistemlerde benzer işlev farklı bir anahtar sözcükle sunuluyor olabilir; bu bilgi sisteme göre değiştiği için kullandığınız ürünün belgesinden teyit edin. Kodunuzu taşıyacaksanız APPLY kullanılan sorguları ayrıca işaretleyin.