Unterabfragen

  • Beitrags-Autor:
  • Beitrags-Kategorie:Abfragen

Einfache Unterabfragen

Nicht immer stehen Tabellen so zur Verfügung, wie wir die Daten benötigen. Gelegentlich müssen wir uns Hilfsabfragen bauen. Eine Abfrage stellt, wie auch eine Tabelle, eine Menge von Datensätzen dar. Insoweit darf sie überall dort verwendet werden, wo wir auch eine Tabelle verwenden können.

Eine solche Abfrage nennen wir dann auch abgeleitete Tabelle.Sie ist in Klammern zu notieren und mit einem Aliasbezeichner zu versehen.

Nehmen Sie an, Sie wollten den Gesamtumsatz ermitteln, den Sie mit zahlenden Kunden gemacht haben. Jedoch wollen Sie nicht alle Kunden in der Analyse berücksichtigen. Sie wollen lediglich die Kunden berücksichtigen, für die mehr als 30 Verleihvorgänge registriert sind.

Nähern wir uns der Problemlösung schrittweise:

  1. Zuerst brauchen wir mal die IDs der Kunden, die uns interessieren. Das sind die, die in der Verleihtabelle (rental) mehr als 30 Verleihvorgänge verzeichnet haben.
  2. Für die in Schritt 1 ermittelten Kunden schauen wir in der Zahlungstabelle nach und addieren sämtliche Zahlungen dieser Kunden zu dem gesuchten Gesamtumsatz.
+-----------+-----+
|customer_id|count|
+-----------+-----+
|550        |32   |
|51         |33   |
|406        |32   |
|176        |37   |
|576        |34   |
|309        |31   |
|390        |33   |
...
(134 Datensätze insgesamt)

Das Ergebnis dieser Abfrage ist eine Tabelle. Diese ist zwar nicht in der Datenbank fix gespeichert, ungeachtet dessen handelt es sich um eine Tabelle. Diese Tabelle können wir so nutzen, als wäre sie eine übliche Tabelle, die wir bis hierhin einfach nur durch ihren jeweiligen Namen als Datenquelle angegeben haben. Dazu schreiben wir die Abfrage in runden Klammern in die FROM– oder JOIN-Klausel. Wir müssen darauf achten, ihr einen Aliasbezeichner mitzugeben. So geschehen, behandelt SQL die Abfrage wie eine handelsübliche Tabelle. Wir können nun Schritt 2 der Lösung implementieren. Dazu verknüpfen wir unsere abgeleitete Tabelle mit der Zahlungstabelle über das Attribut customer_id.

Die abgeleitete Tabelle, hier kurz als c bezeichnet, liefert die für uns relevanten Kunden-IDs, für welche wir im zweiten Schritt die geleisteten Zahlungen, als Ist-Umsatz interpretiert, aufsummieren.

+--------+
|total   |
+--------+
|17560.65|
+--------+

Unterabfragen können auch als reine Vergleichsdatenlieferanten eingesetzt werden. In diesem Fal, in der WHERE-Klausel platziert, benötigen Sie keinen Alias-Bezeichner.

Ermitteln wir die Summe aller Umsätze je Kunde. In die Analyse sollen lediglich die Umsätze einfließen, die überdurchschnittlich sind. Wir überlegen uns wieder die erforderlichen Schritte:

  1. Wie groß ist der Durchschnittsumsatz?
  2. Summiere alle Umsätze pro Kunde, wenn der jeweils getätigte Umsatz über dem Durchschnittsumsatz liegt.
+------------------+
|avg               |
+------------------+
|4.2006056453822965|
+------------------+

Der Durchschnittsumsatz ist eine einzige Zahl. Das ist wichtig zu beachten. Eine einzelne Zahl können wir in einer Bedingung, die zwei Werte miteinander vergleicht direkt als Vergleichswert nutzen.

Beachten Sie, den >-Operator nur deshalb nutzen zu können, weil die Unterabfrage nur einen einzigen Wert liefert! Sie können keinen atomaren Wert wie amount mit einer Tabelle mit mehreren Zeilen und/oder Spalten vergleichen.

+---------+----------+------+
|last_name|first_name|total |
+---------+----------+------+
|Abney    |Rafael    |73.88 |
|Adam     |Nathaniel |83.88 |
|Adams    |Kathleen  |65.89 |
|Alexander|Diana     |70.87 |
|Allard   |Gordon    |134.79|
...
(599 Datensätze insgesamt)

Freilich können wir Unterabfragen nicht nur als Ersatz für Tabellen oder als Vergleichslieferanten in Datensatzauswahlbedingungen nutzen. Auch in der Gruppenauswahl können wir Unterabfragen einsetzen. Und wir können das Ganze beliebig komplex gestalten.

Betrachten wir die vordergründig einfache Frage: Welchen Umsatz haben wir mit Kunden getätigt, deren Gesamtumsatz jeweils überdurchschnittlich hoch ist?

  1. Wie hoch sind die Gesamtumsätze je Kunde?
  2. Wie hoch ist der Durchschnittliche Umsatz pro Kunde?
  3. Summiere die Umsätze pro Kunde, wenn dieser zu den überdurchschnittlichen Kunden zählt.

Erfahrene SQL-Programmierer erstellen die Abfrage in einem Schritt. Wir nähern uns der Lösung wieder schrittweise. So sehen Sie die Entwicklung auch komplexer Abfragen.

+--------------------+
|avg_amount          |
+--------------------+
|102.3573288814691152|
+--------------------+

Das ist nun wieder ein einzelner Wert, den wir in üblichen Vergleichen, diesmal in der Gruppenauswahlbedingung, einsetzen können.

Die eingefügten Kommentare spiegeln die Schritte wieder, die ich oben beschrieben habe.

Die obigen Unterabfragen sind so formuliert, dass sie jeweils nur einen Datensatz liefern. Unterabfragen können und dürfen aber auch mehrere Datensätze zurückgeben. Wir müssen lediglich darauf achten, die korrekten Vergleichsoperatoren zu verwenden. Beachten Sie mögliche Schachtelungen, wie wir sie oben genutzt haben.

Liefert eine Unterfrage mehr als einen Datensatz, so können wir beispielsweise mit IN prüfen ob ein Attributwert der äußeren Abfrage in der Ergebnis menge der Unterabfrage enthalten ist. Vergleiche auf größer oder kleiner können mit den Schlüsselworten ALL oder ANY qualifiziert werden. ALL bedeutet dann, dass der Vergleich für alle Datensätze der Unterabfrage zutreffen muss. ANY bedeutet, dass der Vergleich für mindestens einen Datensatz der Unterabfrage zutreffen muss.

Mit EXISTS kann geprüft werden, ob die Unterabfrage überhaupt einen Datensatz geliefert hat. EXISTS liefert TRUE (wahr), wenn mindestens ein Datensatz vorhanden ist, ansonsten liefert EXISTS den Wert FALSE (falsch).

Korrelierte Unterabfragen

Bisher waren alle Unterabfragen, die wir geschrieben haben,auch separat ausführbar. Nehmen Sie jedoch an, Sie wollten die Summe aller überdurchschnittlichen Zahlungen pro Kunde ermitteln. Dabei beziehen wir uns nicht auf die durchschnittliche Zahlungshöhe aller Kunden, sondern auf die durchschnittliche Zahlungshöhe je Kunde.

Um die Aufgabe zu lösen, benötigen Sie pro Kunndendatensatz, den Sie ausgeben, die Höhe der durchschnittlichen Zahlungen. Alle darüber liegenden Zahlungen summieren Sie dann, natürlich pro Kunde auf.

Um die Höhe der durchschnittliche Zahlungen pro Kunde zu ermitteln, brauchen Sie eine Unterabfrage, die für jeden Kunden individuell ausgeführt wird. Sie muss daher auf die Oberabfrage Bezug nehmen. Im Folgenden Beispiel verbindet daher die customer_id Ober- und Unterabfrage. Die customer_id der Unterabfrage muss der customer_id der Oberabfrage entsprechen, die deshalb mit p1 qualifiziert wird, um eindeutig ansprechbar zu sein.

Die Unterabfrage lässt sich nun nicht mehr separat ausführen. Wir nennen eine solche Unterabfrage korrelierte Unterabfrage.

+-----------+---------+----------+------+
|customer_id|last_name|first_name|total |
+-----------+---------+----------+------+
|526        |Seal     |Karl      |162.76|
|148        |Hunt     |Eleanor   |157.76|
|459        |Collazo  |Tommy     |144.79|
|144        |Shaw     |Clara     |141.79|
|403        |Way      |Mike      |130.79|
...
(599 Datensätze insgesamt)