Grundlegende Informationen zu Unterabfragen

Eine Unterabfrage ist eine Abfrage, die in einer SELECT-, INSERT-, UPDATE- oder DELETE-Anweisung bzw. in einer anderen Unterabfrage geschachtelt ist. Eine Unterabfrage kann überall dort verwendet werden, wo ein Ausdruck zulässig ist. In diesem Beispiel wird eine Unterabfrage als Spaltenausdruck namens MaxUnitPrice in einer SELECT-Anweisung verwendet.

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

Eine Unterabfrage wird auch innere Abfrage oder innere SELECT-Anweisung genannt, während die Anweisung mit einer Unterabfrage als äußere Abfrage oder äußere SELECT-Anweisung bezeichnet wird.

Viele Transact-SQL-Anweisungen, die Unterabfragen einschließen, können auch als Verknüpfungen formuliert werden. Andere Fragestellungen können nur mithilfe von Unterabfragen formuliert werden. In Transact-SQL gibt es normalerweise keinen Leistungsunterschied zwischen einer Anweisung, die eine Unterabfrage enthält, und einer semantisch gleichbedeutenden Version ohne Unterabfrage. In manchen Fällen, in denen das Vorhandensein bestimmter Daten überprüft werden muss, wird mit einem Join jedoch eine bessere Leistung erzielt. Denn ansonsten muss die geschachtelte Abfrage für jedes einzelne Ergebnis der äußeren Abfrage verarbeitet werden, damit die Entfernung von Duplikaten sichergestellt ist. In solchen Fällen erzielt ein Join bessere Ergebnisse. Das folgende Beispiel zeigt eine SELECT-Anweisung, die mit einer Unterabfrage erstellt wurde, und eine SELECT-Anweisung, die mit einer Join erstellt wurde. Beide geben dasselbe Resultset zurück.

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

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

Eine Unterabfrage, die in einer äußeren SELECT-Anweisung geschachtelt ist, besitzt folgende Komponenten:

  • Eine reguläre SELECT-Abfrage mit den normalen Auswahllistenkomponenten.

  • Eine reguläre FROM-Klausel mit einem oder mehreren Tabellen- oder Sichtnamen.

  • Eine optionale WHERE-Klausel.

  • Eine optionale GROUP BY-Klausel.

  • Eine optionale HAVING-Klausel.

Die SELECT-Abfrage einer Unterabfrage wird immer in Klammern eingeschlossen. Sie kann keine COMPUTE- oder FOR BROWSE-Klausel enthalten und darf nur dann eine ORDER BY-Klausel einschließen, wenn auch eine TOP-Klausel angegeben ist.

Eine Unterabfrage kann in der WHERE- oder HAVING-Klausel einer äußeren SELECT-, INSERT-, UPDATE- oder DELETE-Anweisung oder in einer anderen Unterabfrage geschachtelt sein. Bis zu 32 Schachtelungsebenen sind möglich. Allerdings variiert das Limit in Abhängigkeit vom verfügbaren Arbeitsspeicher und der Komplexität anderer Ausdrücke in der Abfrage. Einzelne Abfragen unterstützen möglicherweise keine Schachtelung bis zu 32 Ebenen. Sofern eine Unterabfrage einen einzelnen Wert zurückgibt, kann sie in allen Fällen auftreten, in denen auch ein Ausdruck verwendet werden kann.

Wenn eine Tabelle nur in einer Unterabfrage, jedoch nicht in der äußeren Abfrage verwendet wird, können Spalten aus dieser Tabelle nicht in die Ausgabe (die Auswahlliste der äußeren Abfrage) eingeschlossen werden.

Anweisungen, die eine Unterabfrage einschließen, besitzen in der Regel eines der folgenden Formate:

  • WHERE expression [NOT] IN (subquery)

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

  • WHERE [NOT] EXISTS (subquery)

In manchen Transact-SQL-Anweisungen kann die Unterabfrage wie eine unabhängige Abfrage ausgewertet werden. Im Prinzip werden die Ergebnisse der Unterabfrage in die äußere Abfrage eingesetzt (auch wenn Microsoft SQL Server Transact-SQL-Anweisungen mit Unterabfragen nicht unbedingt auf diese Weise verarbeitet).

Es gibt drei grundlegende Arten von Unterabfragen. Arten:

  • Unterabfragen, die Listen bearbeiten und mit IN eingeleitet werden, oder Unterabfragen, die mit einem durch ANY oder ALL geänderten Vergleichsoperator eingeleitet werden.

  • Unterabfragen, die mit einem nicht geänderten Vergleichsoperator eingeleitet werden und einen einzelnen Wert zurückgeben müssen.

  • Unterabfragen, die mit EXISTS eingeleitete Tests auf Vorhandensein bestimmter Daten darstellen.