Verwenden von skalaren oder mehrwertigen Unterabfragen

Abgeschlossen

Eine skalare Unterabfrage ist eine innere SELECT-Anweisung innerhalb einer äußeren Abfrage, die so geschrieben wird, dass sie einen einzelnen Wert zurückgibt. Skalare Unterabfragen können in einer äußeren T-SQL-Anweisung überall dort verwendet werden, wo ein einwertiger Ausdruck zulässig ist – also etwa in einer SELECT-Klausel, in einer WHERE-Klausel, in einer HAVING-Klausel oder sogar in einer FROM-Klausel. Sie können auch in Datenänderungsanweisungen wie UPDATE oder DELETE verwendet werden.

Mehrwertige Unterabfragen können, wie der Name schon sagt, mehrere Zeilen zurückgeben. Sie geben jedoch weiterhin eine einzelne Spalte zurück.

Skalare Unterabfragen

Angenommen, Sie möchten die Details der letzten Bestellung abrufen, die aufgegeben wurde, unter der Annahme, dass es sich um die Bestellung mit dem höchsten SalesOrderID-Wert handelt.

Um den höchsten SalesOrderID-Wert zu ermitteln, können Sie die folgende Abfrage verwenden:

SELECT MAX(SalesOrderID)
FROM Sales.SalesOrderHeader

Diese Abfrage gibt einen einzelnen Wert zurück, der den höchsten Wert für eine OrderID in der SalesOrderHeader-Tabelle angibt.

Um die Details für diese Bestellung abzurufen, müssen Sie möglicherweise die SalesOrderDetails-Tabelle nach dem Wert filtern, der von der Abfrage oben zurückgegeben wird. Sie können diese Aufgabe ausführen, indem Sie die Abfrage zum Abrufen der maximalen SalesOrderID innerhalb der WHERE-Klausel einer Abfrage schachteln, die die Auftragsdetails abruft.

SELECT SalesOrderID, ProductID, OrderQty
FROM Sales.SalesOrderDetail
WHERE SalesOrderID = 
   (SELECT MAX(SalesOrderID)
    FROM Sales.SalesOrderHeader);

Beachten Sie die folgenden Richtlinien, um eine skalare Unterabfrage zu schreiben:

  • Um eine Abfrage als Unterabfrage zu kennzeichnen, schließen Sie sie in Klammern ein.
  • Mehrere Ebenen von Unterabfragen werden in Transact-SQL unterstützt. In diesem Modul werden nur Abfragen mit zwei Ebenen (eine innere Abfrage innerhalb einer äußeren Abfrage) berücksichtigt, aber bis zu 32 Ebenen werden unterstützt.
  • Wenn die Unterabfrage keine Zeilen zurückgibt (ein leerer Satz), ist das Ergebnis der Unterabfrage NULL. Wenn es in Ihrem Szenario möglich ist, dass keine Zeilen zurückgegeben werden, sollten Sie sicherstellen, dass ihre äußere Abfrage zusätzlich zu anderen erwarteten Ergebnissen NULL ordnungsgemäß verarbeiten kann.
  • Die innere Abfrage sollte in der Regel eine einzelne Spalte zurückgeben. Das Auswählen mehrerer Spalten in einer Unterabfrage ist fast immer ein Fehler. Die einzige Ausnahme besteht dann, wenn die Unterabfrage mit dem EXISTS-Schlüsselwort eingeführt wird.

Eine skalare Unterabfrage kann überall dort in einer Abfrage verwendet werden, wo ein Wert erwartet wird, einschließlich der SELECT-Liste. Wir könnten beispielsweise die Abfrage, die Details für die letzte Bestellung abgerufen hat, um die durchschnittliche Menge der bestellten Artikel erweitern, sodass wir die in der letzten Bestellung bestellte Menge mit dem Durchschnitt für alle Bestellungen vergleichen können.

SELECT SalesOrderID, ProductID, OrderQty,
    (SELECT AVG(OrderQty)
     FROM SalesLT.SalesOrderDetail) AS AvgQty
FROM SalesLT.SalesOrderDetail
WHERE SalesOrderID = 
    (SELECT MAX(SalesOrderID)
     FROM SalesLT.SalesOrderHeader);

Mehrwertige Unterabfragen

Eine mehrwertige Unterabfrage eignet sich gut zum Zurückgeben von Ergebnissen mit dem IN-Operator. Im folgenden hypothetischen Beispiel werden die Werte CustomerID und SalesOrderID für alle Bestellungen von Kunden in Kanada zurückgegeben.

SELECT CustomerID, SalesOrderID
FROM Sales.SalesOrderHeader
WHERE CustomerID IN (
    SELECT CustomerID
    FROM Sales.Customer
    WHERE CountryRegion = 'Canada');

Wenn Sie in diesem Beispiel nur die innere Abfrage ausführen würden, würde eine Spalte mit CustomerID-Werten zurückgegeben, die eine Zeile für jeden Kunden in Kanada enthält.

In vielen Fällen können mehrwertige Unterabfragen problemlos mit Joins geschrieben werden. Hier sehen Sie beispielsweise eine Abfrage, die einen Join verwendet, um die gleichen Ergebnisse wie im vorherigen Beispiel zurückzugeben:

SELECT c.CustomerID, o.SalesOrderID
FROM Sales.Customer AS c
JOIN Sales.SalesOrderHeader AS o
    ON c.CustomerID = o.CustomerID
WHERE c.CountryRegion = 'Canada';

Wie entscheiden Sie also, ob eine Abfrage mit mehreren Tabellen als JOIN oder mit einer Unterabfrage geschrieben werden soll? Manchmal hängt dies einfach davon ab, womit Sie sich wohler fühlen. Die meisten geschachtelten Abfragen, die problemlos in JOINs konvertiert werden können, WERDEN intern tatsächlich in einen JOIN konvertiert. Für solche Abfragen gibt es dann keinen wirklichen Unterschied beim Schreiben der Abfrage auf die eine oder andere Weise.

Eine Einschränkung, die Sie beachten sollten, ist, dass bei Verwendung einer geschachtelten Abfrage die an den Client zurückgegebenen Ergebnisse nur Spalten aus der äußeren Abfrage enthalten können. Wenn Sie also Spalten aus beiden Tabellen zurückgeben müssen, sollten Sie die Abfrage mit einem JOIN schreiben.

Zudem gibt es Situationen, in denen die innere Abfrage wesentlich kompliziertere Vorgänge ausführen muss als die einfachen Abrufe in unseren Beispielen. Das Umschreiben komplexer Unterabfragen mit einem JOIN kann schwierig sein. Viele SQL-Entwickler finden, dass Unterabfragen am besten für komplizierte Verarbeitungsvorgänge geeignet sind, weil sie es ermöglichen, die Verarbeitung in kleinere Schritte zu unterteilen.