Alt Sorgular (SQL Server)

Şunlar için geçerlidir:SQL ServerAzure SQL VeritabanıAzure SQL Yönetilen ÖrneğiAzure Synapse AnalyticsAnalitik Platform Sistemi (PDW)Microsoft Fabric'te SQL veritabanı

Alt sorgu, bir SELECT, INSERT, UPDATE veya DELETE deyiminin ya da başka bir alt sorgunun içine iç içe yerleştirilmiş bir sorgudur.

Bu makaledeki kod örneklerinde AdventureWorks2025 veya AdventureWorksDW2025 örnek veritabanı kullanılır; bunları Microsoft SQL Server Samples and Community Projects ana sayfasından indirebilirsiniz.

Alt sorgu, bir ifadeye izin verilen her yerde kullanılabilir. Bu örnekte, bir alt sorgu, SELECT deyiminde MaxUnitPrice adlı bir sütun ifadesi olarak kullanılır.

USE AdventureWorks2022;
GO
SELECT Ord.SalesOrderID, Ord.OrderDate,
    (SELECT MAX(OrdDet.UnitPrice)
     FROM Sales.SalesOrderDetail AS OrdDet
     WHERE Ord.SalesOrderID = OrdDet.SalesOrderID) AS MaxUnitPrice
FROM Sales.SalesOrderHeader AS Ord;
GO

Alt sorgu temelleri

Alt sorgu, iç sorgu veya iç seçim olarak da adlandırılırken, alt sorgu içeren deyim dış sorgu veya dış seçim olarak da adlandırılır.

Alt sorgular içeren birçok Transact-SQL deyimi alternatif olarak birleşim olarak formüle edilebilir. Diğer sorular yalnızca alt sorgularla sorulabilir. Transact-SQL'de, alt sorgu içeren bir deyim ile alt sorgu içermeyen ancak anlamsal olarak eşdeğer bir sürüm arasında genellikle performans açısından fark yoktur. SQL Server'ın sorguları nasıl işlediği hakkında mimari bilgi için bkz. SQL deyimi işleme. Ancak, varlığın denetlenilmesi gereken bazı durumlarda birleştirme daha iyi performans sağlar. Aksi takdirde, yinelenenlerin ortadan kaldırılmasını sağlamak için iç içe sorgunun dış sorgunun her sonucu için işlenmesi gerekir. Böyle durumlarda birleştirme yaklaşımı daha iyi sonuçlar verir.

Aşağıdaki örnekte hem bir alt sorgu SELECT hem de aynı sonuç kümesini ve yürütme planını döndüren bir birleşim SELECT gösterilmektedir:

USE AdventureWorks2022;
GO

/* SELECT statement built using a subquery. */
SELECT [Name]
FROM Production.Product
WHERE ListPrice =
    (SELECT ListPrice
     FROM Production.Product
     WHERE [Name] = 'Chainring Bolts' );
GO

/* SELECT statement built using a join that returns
   the same result set. */
SELECT Prd1.[Name]
FROM Production.Product AS Prd1
     JOIN Production.Product AS Prd2
       ON (Prd1.ListPrice = Prd2.ListPrice)
WHERE Prd2.[Name] = 'Chainring Bolts';
GO

Dış SELECT deyimde iç içe yerleştirilmiş bir alt sorgu aşağıdaki bileşenlere sahiptir:

  • Normal SELECT seçme listesi bileşenlerini içeren normal bir sorgu.
  • Bir veya daha fazla tablo veya görünüm adı içeren normal FROM tümce.
  • İsteğe bağlı bir WHERE yan tümce.
  • İsteğe bağlı bir GROUP BY yan tümce.
  • İsteğe bağlı HAVING yan tümcesi.

Bir SELECT alt sorgunun sorgusu her zaman parantez içine alınır. Bu, COMPUTE veya FOR BROWSE yan tümcesi içeremez ve yalnızca TOP yan tümcesi de belirtildiğinde ORDER BY yan tümcesini içerebilir.

Bir alt sorgu, dış SELECT, INSERT, UPDATE veya DELETE deyiminin WHERE ya da HAVING yan tümcesi içinde ya da başka bir alt sorgunun içinde iç içe yer alabilir. Sınır kullanılabilir belleğe ve sorgudaki diğer ifadelerin karmaşıklığına bağlı olarak değişse de en fazla 32 iç içe yerleştirme düzeyi mümkündür. Tekil sorgular, 32 düzeye kadar iç içe geçmeyi desteklemez. Bir alt sorgu, tek bir değer döndürüyorsa bir ifadenin kullanabildiği her yerde görüntülenebilir.

Tablo dış sorguda değil de yalnızca alt sorguda görünüyorsa, bu tablodaki sütunlar çıkışa (dış sorgunun seçme listesi) eklenemez.

Alt sorgu içeren deyimler genellikle şu biçimlerden birini alır:

  • WHERE expression [NOT] IN (subquery)
  • WHERE expression comparison_operator [ANY | ALL] (subquery)
  • WHERE [NOT] EXISTS (subquery)

Bazı Transact-SQL deyimlerinde, alt sorgu bağımsız bir sorgu gibi değerlendirilebilir. Kavramsal olarak, alt sorgu sonuçları dış sorgunun içine yerleştirilir (ancak bu, SQL Server'ın alt sorgu içeren Transact-SQL deyimlerini gerçekte bu şekilde işlediği anlamına gelmez).

Üç temel alt sorgu türü vardır. Şunlar:

  • IN ile sunulan veya ANY ya da ALL ile değiştirilen bir karşılaştırma işleci tarafından değiştirilen listeler üzerinde işlem yapın.
  • Değiştirilmemiş bir karşılaştırma işleci ile tanıtılır ve tek bir değer döndürmesi gerekir.
  • EXISTS ile sunulan varlık testleri mi?

Alt sorgu kuralları

Alt sorgu aşağıdaki kısıtlamalara tabidir:

  • Bir karşılaştırma işleciyle kullanılan bir alt sorgunun SELECT listesi yalnızca bir ifade veya sütun adı içerebilir (EXISTS ve IN öğelerinin sırasıyla SELECT * ya da bir liste üzerinde işlem yapması durumu dışında).
  • Dış sorgunun WHERE yan tümcesi bir sütun adı içeriyorsa, alt sorgu seçme listesindeki sütunla birleştirme uyumlu olmalıdır.
  • Ntext, metin ve görüntü veri türleri, seçme alt sorgu listesinde kullanılamaz.
  • Tek bir değer döndürmeleri gerektiğinden, değiştirilmemiş bir karşılaştırma işleciyle kullanılan alt sorgular (yani ardından ANY veya ALL anahtar sözcüğü gelmeyen bir işleçle) GROUP BY ve HAVING tümcelerini içeremez.
  • anahtar DISTINCT sözcüğü, içeren GROUP BYalt sorgularla kullanılamaz.
  • COMPUTE ve INTO tümceleri belirtilemez.
  • ORDER BY, yalnızca TOP de belirtildiğinde belirtilebilir.
  • Alt sorgu kullanılarak oluşturulan görünüm güncelleştirilemez.
  • kurala göre ile EXISTSsunulan bir alt sorgunun seçme listesinde tek sütun adı yerine yıldız işareti (*) bulunur. ile EXISTS sunulan bir alt sorgunun kuralları standart seçim listesiyle aynıdır çünkü ile sunulan EXISTS bir alt sorgu bir varlık testi oluşturur ve veriler yerine DOĞRU veya YANLIŞ döndürür.

Alt sorgulardaki sütun adlarını niteleme

Aşağıdaki örnekte, dış sorgunun yan tümcesindeki sütun, BusinessEntityID dış sorgu WHERE yan tümcesindeki (FROM) tablo adıyla örtük olarak nitelenmiş durumdadır.Sales.Store Alt sorgunun seçim listesindeki CustomerID başvurusu, alt sorgunun FROM tümcesi, yani Sales.Customer tablosu tarafından nitelenir.

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Sales.Store
WHERE BusinessEntityID NOT IN
    (SELECT CustomerID
     FROM Sales.Customer
     WHERE TerritoryID = 5);
GO

Genel kural, bir ifadedeki sütun adlarının aynı düzeydeki FROM yan tümcesinde başvurulan tablo ile örtük olarak nitelendirilmesidir. Bir alt sorgunun FROM yan tümcesinde başvurulan tabloda bir sütun yoksa, bu sütun dış sorgunun FROM yan tümcesinde başvurulan tablo tarafından örtük olarak nitelenir.

Bu örtük varsayımlar belirtildiğinde sorgu aşağıdaki gibi görünür:

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Sales.Store
WHERE Sales.Store.BusinessEntityID NOT IN
    (SELECT Sales.Customer.CustomerID
     FROM Sales.Customer
     WHERE TerritoryID = 5);
GO

Tablo adını açıkça belirtmek hiçbir zaman yanlış değildir ve açık niteliklere sahip tablo adları hakkındaki örtük varsayımları geçersiz kılmak her zaman mümkündür.

Önemli

Bir alt sorguda bir sütuna başvuruluyorsa, bu sütun alt sorgunun FROM yan tümcesinde başvurulan tabloda bulunmuyor, ancak dış sorgunun FROM yan tümcesinde başvurulan bir tabloda bulunuyorsa, sorgu hata vermeden yürütülür. SQL Server, alt sorgudaki sütunu örtük olarak dış sorgudaki tablo adıyla niteler.

Birden çok iç içe geçme düzeyi

Bir alt sorgu bir veya daha fazla alt sorgu içerebilir. Bir ifadede istediğiniz sayıda alt sorgu iç içe yerleştirilebilir.

Aşağıdaki sorgu, aynı zamanda satış elemanı olan çalışanların adlarını bulur.

USE AdventureWorks2022;
GO
SELECT LastName, FirstName
FROM Person.Person
WHERE BusinessEntityID IN
    (SELECT BusinessEntityID
     FROM HumanResources.Employee
     WHERE BusinessEntityID IN
        (SELECT BusinessEntityID
         FROM Sales.SalesPerson)
    );
GO

Sonuç kümesi aşağıdadır.

LastName                                           FirstName
-------------------------------------------------- -----------------------
Jiang                                              Stephen
Abbas                                              Syed
Alberts                                            Amy
Ansman-Wolfe                                       Pamela
Campbell                                           David
Carson                                             Jillian
Ito                                                Shu
Mitchell                                           Linda
Reiter                                             Tsvi
Saraiva                                            Jos
Vargas                                             Garrett
Varkey Chudukatil                                  Ranjit
Valdez                                             Rachel
Tsoflias                                           Lynn
Pak                                                Jae
Blythe                                             Michael
Mensa-Annan                                        Tete

(17 row(s) affected)

En içteki sorgu, satış temsilcisi kimliklerini döndürür. Bir sonraki üst düzeydeki sorgu, bu satış elemanı kimlikleriyle değerlendirilir ve çalışanların kişi kimliği numaralarını döndürür. Son olarak, dış sorgu çalışanların adlarını bulmak için kişi kimlik numaralarını kullanır.

Bu sorguyu birleştirme olarak da ifade edebilirsiniz:

USE AdventureWorks2022;
GO
SELECT LastName, FirstName
FROM Person.Person c
INNER JOIN HumanResources.Employee e
ON c.BusinessEntityID = e.BusinessEntityID
JOIN Sales.SalesPerson s
ON e.BusinessEntityID = s.BusinessEntityID;
GO

Bağıntılı alt sorgular

Birçok sorgu, alt sorguyu bir kez yürütüp sonuçta elde edilen değeri veya değerleri WHERE dış sorgunun yan tümcesine değiştirerek değerlendirilebilir. Bağıntılı bir alt sorgu (yinelenen alt sorgu olarak da bilinir) içeren sorgularda, alt sorgu değerleri için dış sorguya bağlıdır. Bu, alt sorgunun, dış sorgu tarafından seçilebilen her satır için bir kez tekrar tekrar yürütüldüğünü gösterir.

Bu sorgu, SalesPerson tablosundaki bonusu 5000 olan ve çalışan kimlik numaraları Employee ile SalesPerson tablolarında eşleşen her çalışanın adını ve soyadını tek bir kez getirir.

USE AdventureWorks2022;
GO
SELECT DISTINCT c.LastName, c.FirstName, e.BusinessEntityID
FROM Person.Person AS c JOIN HumanResources.Employee AS e
ON e.BusinessEntityID = c.BusinessEntityID
WHERE 5000.00 IN
    (SELECT Bonus
    FROM Sales.SalesPerson sp
    WHERE e.BusinessEntityID = sp.BusinessEntityID) ;
GO

Sonuç kümesi aşağıdadır.

LastName FirstName BusinessEntityID
-------------------------- ---------- ------------
Ansman-Wolfe Pamela 280
Saraiva José 282

(2 row(s) affected)

Bu deyimdeki önceki alt sorgu, dış sorgudan bağımsız olarak değerlendirilemez. için Employee.BusinessEntityIDbir değere ihtiyacı vardır, ancak SQL Server içindeki Employeefarklı satırları incelediğinden bu değer değişir. Bu sorgu tam olarak şu şekilde değerlendirilir: SQL Server, Employee tablosunun her satırındaki değeri iç sorguda yerine koyarak, her satırın sonuçlara dahil edilip edilmeyeceğini belirler. Örneğin, SQL Server önce Syed Abbas satırını incelerse, Employee.BusinessEntityID değişkeni 285 değerini alır; SQL Server da bu değeri iç sorguda yerine koyar. Bu iki sorgu örneği, bağıntılı alt sorgu ile önceki örneğin ayrıştırma işlemini temsil eden bir örnektir.

USE AdventureWorks2022;
GO
SELECT Bonus
FROM Sales.SalesPerson
WHERE BusinessEntityID = 285;
GO

Sonuç 0,00'dır (Syed Abbas satış temsilcisi olmadıkları için bonus almadım), bu nedenle dış sorgu şu şekilde değerlendirilir:

USE AdventureWorks2022;
GO
SELECT LastName, FirstName
FROM Person.Person AS c JOIN HumanResources.Employee AS e
ON e.BusinessEntityID = c.BusinessEntityID
WHERE 5000 IN (0.00);
GO

Bu yanlış olduğundan, Syed Abbas için olan satır bağıntılı alt sorgu içeren önceki örnek sorgunun sonuçlarında yer almaz. Pamela Ansman-Wolfe satırı için aynı işlemi uygulayın. Sonuçlar içerdiğinden, WHERE 5000 IN (5000) bu satırın sonuçlara dahil olduğunu görürsünüz.

Bağıntılı alt sorgular, tablo değerli işlevin bağımsız değişkeni olarak dış sorgudaki bir tablonun sütunlarına başvurarak, FROM yan tümcesinde tablo değerli işlevler de içerebilir. Bu durumda, dış sorgudaki her satır için tablo değerli işlev, alt sorguya göre değerlendirilir.

Alt sorgu türleri

Alt sorgular birçok yerde belirtilebilir:

Tablo takma adlarıyla alt sorgular

Alt sorgunun ve dış sorgunun aynı tabloya başvuracağı birçok deyim kendi kendine birleşimler (tabloyu kendisine birleştirme) olarak belirtilebilir. Örneğin, bir alt sorgu kullanarak belirli bir durumdaki çalışanların adreslerini bulabilirsiniz:

USE AdventureWorks2022;
GO
SELECT StateProvinceID, AddressID
FROM Person.Address
WHERE AddressID IN
    (SELECT AddressID
     FROM Person.Address
     WHERE StateProvinceID = 39);
GO

Sonuç kümesi aşağıdadır.

StateProvinceID AddressID
----------- -----------
39 942
39 955
39 972
39 22660

(4 row(s) affected)

Ya da kendi kendine birleştirmeyi kullanabilirsiniz:

USE AdventureWorks2022;
GO
SELECT e1.StateProvinceID, e1.AddressID
FROM Person.Address AS e1
INNER JOIN Person.Address AS e2
ON e1.AddressID = e2.AddressID
AND e2.StateProvinceID = 39;
GO

Tablo takma adları e1 ve e2 gereklidir çünkü kendisiyle birleştirilen tablo iki farklı rolde yer alır. Takma adlar, hem iç hem de dış sorguda aynı tabloya başvuran iç içe sorgularda da kullanılabilir.

USE AdventureWorks2022;
GO
SELECT e1.StateProvinceID, e1.AddressID
FROM Person.Address AS e1
WHERE e1.AddressID IN
    (SELECT e2.AddressID
     FROM Person.Address AS e2
     WHERE e2.StateProvinceID = 39);
GO

Tablo takma adlarının açıkça belirtilmesi, alt sorgudaki Person.Address başvurusunun dış sorgudaki başvuruyla aynı şeyi ifade etmediğini netleştirir.

IN ile alt sorgular

(veya ) ile INNOT INsunulan bir alt sorgunun sonucu, sıfır veya daha fazla değerin listesidir. Alt sorgu sonuçları döndürdüğünde dış sorgu bunları kullanır. Aşağıdaki sorgu, Adventure Works Cycles'ın yaptığı tüm tekerlek ürünlerinin adlarını bulur.

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID IN
    (SELECT ProductSubcategoryID
     FROM Production.ProductSubcategory
     WHERE [Name] = 'Wheels');
GO

Sonuç kümesi aşağıdadır.

Name
----------------------------
LL Mountain Front Wheel
ML Mountain Front Wheel
HL Mountain Front Wheel
LL Road Front Wheel
ML Road Front Wheel
HL Road Front Wheel
Touring Front Wheel
LL Mountain Rear Wheel
ML Mountain Rear Wheel
HL Mountain Rear Wheel
LL Road Rear Wheel
ML Road Rear Wheel
HL Road Rear Wheel
Touring Rear Wheel

(14 row(s) affected)

Bu deyim iki adımda değerlendirilir. İlk olarak, iç sorgu adla Wheel (17) eşleşen alt kategori kimlik numarasını döndürür. İkinci olarak, bu değer dış sorguda yerine konur; ardından dış sorgu, Production.Product içindeki alt kategori kimlik numaralarına karşılık gelen ürün adlarını bulur.

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID IN ('17');
GO

Bu ve benzer sorunlar için alt sorgu yerine birleştirme kullanmanın bir farkı, birleştirmenin sonuçta birden çok tablodan sütunları göstermenize olanak tanır. Örneğin, sonuçta ürün alt kategorisinin adını eklemek istiyorsanız birleştirme sürümü kullanmanız gerekir.

USE AdventureWorks2022;
GO
SELECT p.[Name], s.[Name]
FROM Production.Product p
INNER JOIN Production.ProductSubcategory s
ON p.ProductSubcategoryID = s.ProductSubcategoryID
AND s.[Name] = 'Wheels';
GO

Sonuç kümesi aşağıdadır.

Name
LL Mountain Front Wheel Wheels
ML Mountain Front Wheel Wheels
HL Mountain Front Wheel Wheels
LL Road Front Wheel Wheels
ML Road Front Wheel Wheels
HL Road Front Wheel Wheels
Touring Front Wheel Wheels
LL Mountain Rear Wheel Wheels
ML Mountain Rear Wheel Wheels
HL Mountain Rear Wheel Wheels
LL Road Rear Wheel Wheels
ML Road Rear Wheel Wheels
HL Road Rear Wheel Wheels
Touring Rear Wheel Wheels

(14 row(s) affected)

Aşağıdaki sorgu, kredi derecelendirmesi iyi olan, Adventure Works Döngüleri'nin en az 20 ürün sipariş ettiği ve teslim etmek için ortalama sağlama süresi 16 günden az olan tüm satıcıların adını bulur.

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Purchasing.Vendor
WHERE CreditRating = 1
AND BusinessEntityID IN
    (SELECT BusinessEntityID
     FROM Purchasing.ProductVendor
     WHERE MinOrderQty >= 20
     AND AverageLeadTime < 16);
GO

Sonuç kümesi aşağıdadır.

Name
--------------------------------------------------
Compete Enterprises, Inc
International Trek Center
First National Sport Co.
Comfort Road Bicycles
Circuit Cycles
First Rate Bicycles
Jeff's Sporting Goods
Competition Bike Training Systems
Electronic Bike Repair & Supplies
Crowley Sport
Expert Bike Co
Team Athletic Co.
Compete, Inc.

(13 row(s) affected)

İç sorgu değerlendirilir ve alt sorgu niteliklerini karşılayan satıcıların kimlik numaraları oluşturulur. Dış sorgu daha sonra değerlendirilir. Hem iç hem de dış sorgunun yan tümcesine birden fazla koşul WHERE ekleyebilirsiniz.

Birleştirme kullanıldığında, aynı sorgu şu şekilde ifade edilir:

USE AdventureWorks2022;
GO
SELECT DISTINCT [Name]
FROM Purchasing.Vendor v
INNER JOIN Purchasing.ProductVendor p
ON v.BusinessEntityID = p.BusinessEntityID
WHERE CreditRating = 1
  AND MinOrderQty >= 20
  AND AverageLeadTime < 16;
GO

Birleştirme işlemi her zaman bir alt sorgu olarak ifade edilebilir. Bir alt sorgu genellikle birleşim olarak ifade edilebilir ancak her zaman ifade edilmeyebilir. Bunun nedeni birleşimlerin simetrik olmasıdır: tabloya AB her iki sırayla da katılabilir ve aynı yanıtı alabilirsiniz. Bir alt sorgu söz konusu olduğunda aynı durum geçerli değildir.

NOT IN içeren alt sorgular

anahtar sözcüğüyle NOT IN sunulan alt sorgular da sıfır veya daha fazla değerin listesini döndürür. Aşağıdaki sorgu, tamamlanmamış bisikletlerin adlarını bulur.

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID NOT IN
    (SELECT ProductSubcategoryID
     FROM Production.ProductSubcategory
     WHERE [Name] = 'Mountain Bikes'
        OR [Name] = 'Road Bikes'
        OR [Name] = 'Touring Bikes');
GO

Bu ifade join işlemine dönüştürülemez. Buna karşılık gelen eşit olmayan birleştirmenin farklı bir anlamı vardır: Bitmiş bisiklet olmayan bir alt kategoride bulunan ürünlerin adlarını bulur.

UPDATE, DELETE ve INSERT ifadelerinde alt sorgular

Alt sorgular, UPDATE, DELETE, INSERT ve SELECT veri işleme (DML) deyimlerinde iç içe kullanılabilir.

Aşağıdaki örnek, tablodaki sütundaki ListPriceProduction.Product değeri ikiye katlar. WHERE yan tümcesindeki alt sorgu, Product tablosunda güncelleştirilen satırları yalnızca BusinessEntity1540 tarafından sağlananlarla sınırlamak için Purchasing.ProductVendor tablosuna başvurur.

USE AdventureWorks2022;
GO
UPDATE Production.Product
SET ListPrice = ListPrice * 2
WHERE ProductID IN
    (SELECT ProductID
     FROM Purchasing.ProductVendor
     WHERE BusinessEntityID = 1540);
GO

İşte join kullanarak yazılmış eşdeğer bir UPDATE ifade:

USE AdventureWorks2022;
GO
UPDATE Production.Product
SET ListPrice = ListPrice * 2
FROM Production.Product AS p
INNER JOIN Purchasing.ProductVendor AS pv
    ON p.ProductID = pv.ProductID AND BusinessEntityID = 1540;
GO

Diğer alt sorgularda aynı tablonun kendisine başvurulma ihtimaline karşı netlik sağlamak için hedef tablonun diğer adını kullanın:

USE AdventureWorks2022;
GO
UPDATE p
SET ListPrice = ListPrice * 2
FROM Production.Product AS p
INNER JOIN Purchasing.ProductVendor AS pv
    ON p.ProductID = pv.ProductID AND BusinessEntityID = 1540;
GO

Karşılaştırma işleçleri içeren alt sorgular

Alt sorgular karşılaştırma işleçlerinden biriyle (=, , < >>, , > =, <, ! >, ! <veya < =) tanıtılabilir.

Değiştirilmemiş bir karşılaştırma işleciyle (yani ardından ANY veya ALL gelmeyen bir karşılaştırma işleciyle) başlatılan bir alt sorgu, IN ile başlatılan alt sorgularda olduğu gibi bir değerler listesi yerine tek bir değer döndürmelidir. Böyle bir alt sorgu birden fazla değer döndürürse, SQL Server bir hata iletisi görüntüler.

Değiştirilmemiş bir karşılaştırma işleciyle sunulan bir alt sorguyu kullanmak için, verilerinize ve sorunun doğasına göre alt sorgunun tam olarak bir değer döndüreceğini bilecek kadar bilgi sahibi olmanız gerekir.

Örneğin, her satış elemanının yalnızca bir satış bölgesini kapsadığını varsayarsanız ve kapsamındaki bölgede Linda Mitchellbulunan müşterileri bulmak istiyorsanız, basit = karşılaştırma işleciyle birlikte sunulan bir alt sorgu içeren bir deyim yazabilirsiniz.

USE AdventureWorks2022;
GO
SELECT CustomerID
FROM Sales.Customer
WHERE TerritoryID =
    (SELECT TerritoryID
     FROM Sales.SalesPerson
     WHERE BusinessEntityID = 276);
GO

Ancak Linda Mitchell birden fazla satış bölgesini kapsadıysa bir hata iletisiyle sonuçlanır. Karşılaştırma işleci yerine = bir IN formülasyon kullanılabilir (=ANY aynı zamanda çalışır).

Değiştirilmemiş karşılaştırma işleçleriyle sunulan alt sorgular genellikle toplama işlevleri içerir çünkü bunlar tek bir değer döndürür. Örneğin, aşağıdaki deyim, liste fiyatı ortalama liste fiyatından büyük olan tüm ürünlerin adlarını bulur.

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ListPrice >
    (SELECT AVG (ListPrice)
     FROM Production.Product);
GO

Değiştirilmemiş karşılaştırma işleçleriyle kullanılan alt sorguların tek bir değer döndürmesi gerektiğinden, GROUP BY veya HAVING yan tümcelerini, ancak GROUP BY ya da HAVING yan tümcesinin kendisinin tek bir değer döndürdüğünü biliyorsanız içerebilirler. Örneğin, aşağıdaki sorgu içindeki en düşük fiyatlı üründen daha yüksek fiyatlı ürünleri ProductSubcategoryID14bulur.

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ListPrice >
    (SELECT MIN (ListPrice)
     FROM Production.Product
     GROUP BY ProductSubcategoryID
     HAVING ProductSubcategoryID = 14);
GO

ANY, SOME veya ALL ile değiştirilen karşılaştırma işleçleri

Alt sorguya neden olan karşılaştırma işleçleri ALL veya ANYanahtar sözcükleriyle değiştirilebilir. SOME için ANYISO standart eşdeğeridir. Bu karşılaştırma işleçleri hakkında daha fazla bilgi için bkz. SOME | ANY.

Değiştirilmiş bir karşılaştırma işleci kullanılan alt sorgular, sıfır veya daha fazla değer içeren bir liste döndürür ve GROUP BY veya HAVING yan tümcesi içerebilir. Bu alt sorgular EXISTS kullanılarak yeniden ifade edilebilir.

Karşılaştırma işlecini > örnek olarak kullanmak, > ALL her değerden daha büyük anlamına gelir. Başka bir deyişle, en büyük değerden daha büyük anlamına gelir. Örneğin, > ALL (1, 2, 3) 3'ten büyük anlamına gelir. > ANY en az bir değerden büyük, yani minimumdan büyük anlamına gelir. Yani > ANY (1, 2, 3) 1'den büyük demek.

ile alt sorgudaki > ALL bir satırın dış sorguda belirtilen koşulu karşılaması için, alt sorguyu tanıtan sütundaki değerin, alt sorgu tarafından döndürülen değerler listesindeki her değerden büyük olması gerekir.

Benzer şekilde, > ANY bir satırın dış sorguda belirtilen koşulu karşılaması için, alt sorguyu tanıtan sütundaki değerin, alt sorgu tarafından döndürülen değerler listesindeki değerlerden en az birinden büyük olması gerektiği anlamına gelir.

Aşağıdaki sorgu, ANY ile değiştirilmiş bir karşılaştırma işleciyle tanıtılan bir alt sorgunun örneğini verir. Liste fiyatları herhangi bir ürün alt kategorisinin en yüksek liste fiyatından büyük veya buna eşit olan ürünleri bulur.

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ListPrice >= ANY
    (SELECT MAX (ListPrice)
     FROM Production.Product
     GROUP BY ProductSubcategoryID);
GO

Her Product alt kategorisi için iç sorgu en yüksek liste fiyatını bulur. Dış sorgu bu değerlerin tümüne bakar ve hangi ürünün liste fiyatlarının herhangi bir ürün alt kategorisinin en yüksek liste fiyatından büyük veya buna eşit olduğunu belirler. olarak değiştirilirse ANYALL, sorgu yalnızca liste fiyatı iç sorguda döndürülen tüm liste fiyatlarından büyük veya buna eşit olan ürünleri döndürür.

Alt sorgu herhangi bir değer döndürmezse, sorgunun tamamı herhangi bir değer döndüremez.

= ANY işleci ile INeşdeğerdir. Örneğin, Adventure Works Cycles'ın ürettiği tüm tekerlek ürünlerinin adlarını bulmak için IN veya = ANY kullanabilirsiniz.

--Using = ANY
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID = ANY
    (SELECT ProductSubcategoryID
     FROM Production.ProductSubcategory
     WHERE Name = 'Wheels');
GO

--Using IN
USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID IN
    (SELECT ProductSubcategoryID
     FROM Production.ProductSubcategory
     WHERE Name = 'Wheels');
GO

her iki sorgu için de sonuç kümesi aşağıdadır:

Name
--------------------------------------------------
LL Mountain Front Wheel
ML Mountain Front Wheel
HL Mountain Front Wheel
LL Road Front Wheel
ML Road Front Wheel
HL Road Front Wheel
Touring Front Wheel
LL Mountain Rear Wheel
ML Mountain Rear Wheel
HL Mountain Rear Wheel
LL Road Rear Wheel
ML Road Rear Wheel
HL Road Rear Wheel
Touring Rear Wheel

(14 row(s) affected)

Ancak, <> ANY işleci NOT IN öğesinden farklıdır:

  • <> ANY, a'ya eşit değil veya b'ye eşit değil veya c'ye eşit değil anlamına gelir
  • NOT IN not = a, not = b ve not = c anlamına gelir
  • <> ALL ile aynı anlama gelir NOT IN

Örneğin, aşağıdaki sorgu herhangi bir satış elemanı tarafından kapsanmayan bir bölgede bulunan müşterileri bulur.

USE AdventureWorks2022;
GO
SELECT CustomerID
FROM Sales.Customer
WHERE TerritoryID <> ANY
    (SELECT TerritoryID
     FROM Sales.SalesPerson);
GO

Sonuçlar, satış bölgeleri NULLolan müşteriler dışında tüm müşterileri içerir çünkü müşteriye atanan her bölge bir satış sorumlusu tarafından kapsanmaktadır. İç sorgu, satış kişilerinin kapsadığı tüm satış bölgelerini bulur ve her bölge için dış sorgu, tek bir bölgede olmayan müşterileri bulur.

Aynı nedenle, bu sorguda kullandığınızda NOT IN sonuçlar müşterilerden hiçbirini içermez.

<> ALL işleciyle aynı sonuçları elde edebilirsiniz; bu da NOT IN ile eşdeğerdir.

Alt sorgular EXISTS

anahtar sözcüğüyle EXISTSbir alt sorgu sunulduğunda, alt sorgu bir varoluş testi olarak çalışır. Dış WHERE sorgunun yan tümcesi, alt sorgu tarafından döndürülen satırların mevcut olup olmadığını test eder. Alt sorgu gerçekte hiçbir veri üretmez; TRUE veya FALSE değerini döndürür.

ile EXISTS sunulan bir alt sorgu aşağıdaki söz dizimine sahiptir: WHERE [NOT] EXISTS (subquery)

Aşağıdaki sorgu, Wheels alt kategorisindeki tüm ürünlerin adlarını bulur:

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE EXISTS
    (SELECT *
     FROM Production.ProductSubcategory
     WHERE ProductSubcategoryID =
            Production.Product.ProductSubcategoryID
        AND [Name] = 'Wheels');
GO

Sonuç kümesi aşağıdadır.

Name
--------------------------------------------------
LL Mountain Front Wheel
ML Mountain Front Wheel
HL Mountain Front Wheel
LL Road Front Wheel
ML Road Front Wheel
HL Road Front Wheel
Touring Front Wheel
LL Mountain Rear Wheel
ML Mountain Rear Wheel
HL Mountain Rear Wheel
LL Road Rear Wheel
ML Road Rear Wheel
HL Road Rear Wheel
Touring Rear Wheel

(14 row(s) affected)

Bu sorgunun sonuçlarını anlamak için sırayla her ürünün adını göz önünde bulundurun. Bu değer alt sorgunun en az bir satır döndürmesine neden olur mu? Başka bir deyişle, sorgu varlık testinin sonucunun TRUE olmasına neden olur mu?

ile EXISTS sunulan alt sorgular, aşağıdaki yollarla diğer alt sorgulardan biraz farklıdır:

  • Anahtar sözcüğün EXISTS önünde sütun adı, sabit veya başka bir ifade yoktur.
  • tarafından EXISTS tanıtılan bir alt sorgunun seçme listesi neredeyse her zaman yıldız işaretinden (*) oluşur. Yalnızca alt sorguda belirtilen koşullara uyan satırların mevcut olup olmadığını test ettiğiniz için sütun adlarını listelemek için bir neden yoktur.

EXISTS Anahtar sözcük önemlidir çünkü genellikle alt sorgular olmadan alternatif formülasyon yoktur. EXISTS ile oluşturulan bazı sorgular başka hiçbir şekilde ifade edilemese de, birçok sorgu benzer sonuçlar elde etmek için IN ya da ANY veya ALL ile değiştirilmiş bir karşılaştırma işleci kullanabilir.

Örneğin, yukarıdaki sorgu kullanılarak INifade edilebilir:

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE ProductSubcategoryID IN
    (SELECT ProductSubcategoryID
     FROM Production.ProductSubcategory
     WHERE [Name] = 'Wheels');
GO

NOT EXISTS ile alt sorgular

NOT EXISTS, EXISTS gibi çalışır, ancak alt sorgu hiçbir satır döndürmezse WHERE ifadesi karşılanır.

Örneğin, tekerlekler alt kategorisinde olmayan ürünlerin adlarını bulmak için:

USE AdventureWorks2022;
GO
SELECT [Name]
FROM Production.Product
WHERE NOT EXISTS
    (SELECT *
     FROM Production.ProductSubcategory
     WHERE ProductSubcategoryID =
            Production.Product.ProductSubcategoryID
        AND [Name] = 'Wheels');
GO

İfade yerine kullanılan alt sorgular

Transact-SQL'de, bir alt sorgu, ORDER BY listesi dışında, bir ifadenin kullanılabildiği her yerde SELECT, UPDATE, INSERT ve DELETE deyimlerinde kullanılabilir.

Aşağıdaki örnekte bu geliştirmeyi nasıl kullanabileceğiniz gösterilmektedir. Bu sorgu tüm dağ bisikleti ürünlerinin fiyatlarını, bunların ortalama fiyatını ve her dağ bisikletinin fiyatı ile ortalama fiyat arasındaki farkı bulur.

USE AdventureWorks2022;
GO
SELECT [Name], ListPrice,
(SELECT AVG(ListPrice) FROM Production.Product) AS Average,
    ListPrice - (SELECT AVG(ListPrice) FROM Production.Product)
    AS Difference
FROM Production.Product
WHERE ProductSubcategoryID = 1;
GO