Zusammenfassen von Daten mit GROUP BY

Abgeschlossen

Auch wenn Aggregatfunktionen für die Analyse nützlich sind, möchten Sie Ihre Daten vielleicht in Teilmengen anordnen, bevor Sie sie zusammenfassen. In diesem Abschnitt erfahren Sie, wie Sie dies mithilfe der GROUP BY-Klausel erreichen.

Verwenden der GROUP BY-Klausel

Wie Sie gelernt haben, wird bei der Verarbeitung Ihrer SELECT-Anweisung eine virtuelle Tabelle erstellt, nachdem die FROM-Klausel und die WHERE-Klausel ausgewertet wurden. Der Inhalt der virtuellen Tabelle steht jetzt zur weiteren Verarbeitung zur Verfügung. Sie können die GROUP BY-Klausel verwenden, um den Inhalt dieser virtuellen Tabelle in Zeilengruppen zu unterteilen.

Um Zeilen zu gruppieren, geben Sie mindestens ein Element in der GROUP BY-Klausel an:

GROUP BY <value1> [, <value2>, …]

GROUP BY erstellt Gruppen und platziert Zeilen in jeder Gruppe, wie durch die in der Klausel angegebenen Elemente bestimmt.

Die folgende Abfrage führt z. B. zu einem Satz von gruppierten Zeilen, eine Zeile pro CustomerID in der Sales.SalesOrderHeader-Tabelle. Eine andere Art, den GROUP BY-Prozess zu betrachten, besteht darin, dass alle Zeilen mit demselben Wert für CustomerID gruppiert und in einer einzelnen Ergebniszeile zurückgegeben werden.

SELECT CustomerID
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

Die Abfrage oben entspricht der folgenden Abfrage:

SELECT DISTINCT CustomerID
FROM Sales.SalesOrderHeader

Nachdem die GROUP BY-Klausel verarbeitet und jede Zeile einer Gruppe zugeordnet wurde, müssen spätere Phasen der Abfrage alle Elemente der Quellzeilen aggregieren, die sich in der SELECT-Liste befinden, aber nicht in der GROUP BY-Liste vorkommen. Diese Anforderung hat Auswirkungen darauf, wie Sie Ihre SELECT- und HAVING-Klauseln schreiben.

Worin besteht also der Unterschied zwischen dem Schreiben der Abfrage mit GROUP BY oder DISTINCT? Wenn Sie nur die eindeutigen Werte für CustomerID kennen möchten, gibt es keinen Unterschied. Mit GROUP BY können wir der SELECT-Liste jedoch weitere Elemente hinzufügen, die dann für jede Gruppe aggregiert werden.

Die einfachste Aggregatfunktion ist „COUNT(*)“. Die folgende Abfrage verwendet die ursprünglichen 830 Quellzeilen aus CustomerID und gruppiert sie basierend auf den CustomerID-Werten in 89 Gruppen. Jeder eindeutige CustomerID-Wert generiert eine Ausgabezeile in der GROUP BY-Abfrage.

SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

Für jeden CustomerID-Wert aggregiert und zählt die Abfrage die Zeilen, sodass das Ergebnis zeigt, wie viele Zeilen in der SalesOrderHeader-Tabelle zu jedem Kunden gehören.

CustomerID

OrderCount

1234

3

1005

1

Beachten Sie, dass GROUP BY die Reihenfolge der Ergebnisse nicht garantiert. Aufgrund der Art und Weise, wie der Gruppierungsvorgang vom Abfrageprozessor ausgeführt wird, werden die Ergebnisse oft in der Reihenfolge der Gruppenwerte zurückgegeben. Sie sollten sich jedoch nicht auf dieses Verhalten verlassen. Wenn die Ergebnisse sortiert werden müssen, müssen Sie eine ORDER-Klausel explizit angeben:

SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
ORDER BY CustomerID;

Dieses Mal werden die Ergebnisse in der angegebenen Reihenfolge zurückgegeben:

CustomerID

OrderCount

1005

1

1234

3

Die Klauseln in einer SELECT-Anweisung werden in der folgenden Reihenfolge angewendet:

  1. FROM
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT
  6. ORDER BY

Spaltenaliase werden in der SELECT-Klausel zugewiesen, die nach der GROUP BY-Klausel, aber vor der ORDER BY-Klausel auftritt. Sie können in der ORDER BY-Klausel auf einen Spaltenalias verweisen, jedoch nicht in der GROUP BY-Klausel. Die folgende Abfrage führt zu einem Fehler des Typs Ungültiger Spaltenname:

SELECT CustomerID AS Customer,
       COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY Customer
ORDER BY Customer;

Die folgende Abfrage ist jedoch erfolgreich und gruppiert und sortiert die Ergebnisse nach der Kunden-ID.

SELECT CustomerID AS Customer,
       COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
ORDER BY Customer;

Problembehandlung von GROUP BY-Fehlern

Ein häufiges Hindernis für die Verwendung von GROUP BY in SELECT-Anweisungen ist das Verständnis, warum die folgende Art von Fehlermeldung auftritt:

Msg 8120, Level 16, State 1, Line 2 Column <column_name> ist in der Auswahlliste ungültig, da sie weder in der Aggregatfunktion noch in der „GROUP BY“-Klausel enthalten ist.

Die folgende Abfrage ist beispielsweise zulässig, weil jede Spalte in der SELECT-Liste entweder eine Spalte in der GROUP BY-Klausel oder eine Aggregatfunktion ist, die für jede Gruppe verwendet wird:

SELECT CustomerID, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

Die folgende Abfrage gibt einen Fehler zurück, weil PurchaseOrderNumber nicht Teil von GROUP BY ist und nicht mit einer Aggregatfunktion verwendet wird.

SELECT CustomerID, PurchaseOrderNumber, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID;

Diese Abfrage gibt den folgenden Fehler zurück:

Msg 8120, Level 16, State 1, Line 1
Column 'Sales.SalesOrderHeader.PurchaseOrderNumber' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

Hier ist eine weitere Möglichkeit, die Abfrage einzuschätzen. Diese Abfrage gibt eine Zeile für jeden CustomerID-Wert zurück. Zeilen für dieselbe CustomerID können jedoch unterschiedliche PurchaseOrderNumber-Werte aufweisen. Welcher der Werte sollte also zurückgegeben werden?

Wenn Sie Aufträge pro Kunden-ID und Bestellung anzeigen möchten, können Sie der GROUP BY-Klausel die PurchaseOrderNumber-Spalte wie folgt hinzufügen:

SELECT CustomerID, PurchaseOrderNumber, COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID, PurchaseOrderNumber;

Diese Abfrage gibt eine Zeile für jede Kombination aus Kunde und Bestellung zusammen mit der Anzahl der Bestellungen für diese Kombination zurück.