Was ist eigentlich eine Subquery – und wann ist sie sinnvoll?

Typische Aufgabe aus dem Arbeitsalltag eines Informatikers: Du möchtest alle Kunden finden, deren Umsatz über dem Durchschnitt liegt. Wie würdest du das in SQL lösen? Genau hier kommt das Konzept der Subquery ins Spiel. Eine Subquery ist eine „Abfrage in einer Abfrage“ – eine geschachtelte SELECT-Anweisung, die es dir ermöglicht, Zwischenergebnisse zu berechnen und diese in der Hauptabfrage zu verwenden.

In diesem Artikel wirst du die Grundlagen von Subqueries kennenlernen, verstehen, wie sie funktionieren, und sehen, wann sie besonders sinnvoll eingesetzt werden können. Dabei helfen dir praxisnahe Beispiele, um das Konzept greifbar zu machen.

SQL Subquery

Was ist eine Subquery?

Eine Subquery ist eine SQL-Abfrage, die innerhalb einer anderen Abfrage eingebettet ist. Das bedeutet, dass du in einer Hauptabfrage eine weitere SELECT-Anweisung verschachtelst, um Zwischenergebnisse zu ermitteln, die dann in der äußeren Abfrage verwendet werden.

Subqueries können in verschiedenen Teilen einer SQL-Anweisung auftreten, am häufigsten jedoch in der WHERE-Klausel. Sie können aber auch in FROM, SELECT, HAVING oder sogar innerhalb von JOIN-Klauseln verwendet werden.

Eine einfache Analogie ist ein Hilfsrechner, der für die Hauptabfrage Zwischenergebnisse berechnet, die dann weiterverarbeitet werden.

Beispiel einer einfachen Subquery:

SELECT name
FROM customers
WHERE revenue > (SELECT AVG(revenue) FROM customers);

Arten von Subqueries

Subqueries lassen sich nach verschiedenen Kriterien unterscheiden, vor allem nach dem Rückgabewert und der Abhängigkeit von der äußeren Abfrage.

Nach Rückgabewert:

Typ Beschreibung Beispiel-Klausel
Skalare Subquery Gibt einen einzelnen Wert zurück. WHERE salary > (SELECT ...)
Mehrzeilige Subquery Gibt mehrere Werte zurück. WHERE id IN (SELECT ...)
Tabellarische Subquery Gibt eine ganze Tabelle zurück. FROM (SELECT ...) AS sub

Nach Abhängigkeit:

  • Korrelierte Subquery: Bezieht sich auf Daten der äußeren Abfrage. Sie wird für jede Zeile der äußeren Abfrage neu ausgeführt.
    Beispiel: WHERE EXISTS (SELECT ... WHERE outer.id = inner.id)
  • Nicht-korrelierte Subquery: Läuft unabhängig von der äußeren Abfrage und wird nur einmal ausgeführt.

Typische Anwendungsfälle (Wann ist sie sinnvoll?)

Fall 1: Vergleich mit Aggregatwerten

Problem: Zeige alle Produkte, die teurer als der Durchschnitt sind.

Lösung:

SELECT product_name, price
FROM products
WHERE price > (SELECT AVG(price) FROM products);

Fall 2: Dynamische Filterung mit IN oder NOT IN

Problem: Welche Kunden haben noch nie bestellt?

Lösung:

SELECT customer_id
FROM customers
WHERE customer_id NOT IN (SELECT DISTINCT customer_id FROM orders);

Fall 3: Korrelierte Subqueries für zeilenweise Prüfung

Problem: Finde alle Mitarbeiter, die mehr als ihr Team-Durchschnitt verdienen.

Lösung:

SELECT employee_id, salary, team_id
FROM employees e1
WHERE salary > (SELECT AVG(salary)
                  FROM employees e2
                  WHERE e1.team_id = e2.team_id);

Fall 4: Tabellarische Subqueries als Datenquelle

Problem: Berechne den monatlichen Umsatz aus einer Detailtabelle.

Lösung:

SELECT month, SUM(sales)
FROM (SELECT DATE_TRUNC('month', order_date) AS month, amount AS sales
      FROM orders) AS sub
GROUP BY month;

Vorteile vs. Nachteile

Vorteile:

  • Lesbarkeit: Komplexe Logik wird in Teilschritte zerlegt, was den Code übersichtlicher macht.
  • Flexibilität: Subqueries ersetzen manuelle Zwischenschritte wie temporäre Tabellen.
  • Präzision: Ideal für Einzelwertvergleiche oder Existenzprüfungen mit EXISTS.

Nachteile & Risiken:

  • Performance: Korrelierte Subqueries können langsam sein, da sie pro Zeile der äußeren Abfrage ausgeführt werden.
  • Alternativen: Manchmal sind JOIN-Operationen oder CTEs (Common Table Expressions) effizienter.
  • Debugging: Verschachtelte Queries sind oft schwerer zu testen und zu verstehen.

Faustregel: Verwende eine Subquery, wenn sie klarer und kürzer als ein JOIN ist – aber überprüfe immer die Performance.

Best Practices

  • Vermeide korrelierte Subqueries, wenn eine JOIN-basierte Lösung ähnlich effizient ist.
  • Nutze EXISTS statt IN, wenn du nur auf Existenz prüfen möchtest – das ist oft performanter.
  • Setze bei tiefen Verschachtelungen lieber CTEs (Common Table Expressions) ein, um die Lesbarkeit zu erhöhen:
    WITH avg_sales AS (SELECT AVG(amount) FROM orders)
    SELECT *
    FROM products
    WHERE price > (SELECT * FROM avg_sales);
        
  • Teste die Performance deiner Queries mit Tools wie EXPLAIN in PostgreSQL oder EXPLAIN PLAN in Oracle.

Fazit: Mächtiges Werkzeug für komplexe Anforderungen

Subqueries sind ein mächtiges Werkzeug, um komplexe Filterungen, Aggregationen oder Vergleiche in SQL umzusetzen. Sie eignen sich besonders gut für:

  • Einzelwertvergleiche
  • Dynamische Listen mit IN oder NOT IN
  • Existenzprüfungen mit EXISTS

Allerdings solltest du immer abwägen zwischen Lesbarkeit und Performance. Bei großen Datenmengen sind oft CTEs oder JOINs die bessere Wahl.