Zum Inhalt
wannacode

Bäume und Folgen: WITH RECURSIVE

Kurz gesagt: WITH RECURSIVE ist eine Abfrage mit einem Schritt, der sein eigenes Ergebnis liest, sodass sie Bäume wie Kategorien durchlaufen oder eine Folge von Daten erzeugen kann.

Problem

Der Pfad zur Kategorie

Über jedem Produkt zeigt die Website den Pfad dorthin: „Lebensmittel > Milchprodukte“. Die Kategorien sind ein Baum: Jede hat ein parent_id, das auf die Kategorie über ihr zeigt. Mit einem Self Join aus dem Modul über das Verbinden geht das so:

SQLDatenbank: Shop

Das funktioniert, weil der Baum zwei Ebenen hat. Wenn morgen „Käse“ unter „Milchprodukte“ auftaucht, brauchst du einen Join mehr, und für vier Ebenen wieder einen mehr. Du weißt nicht im Voraus, wie viele Ebenen es werden.

Die Idee

Ein Schritt, der sich selbst liest

Mit WITH RECURSIVE kann ein Schritt seine eigenen Zeilen lesen. Hier das kleinste Beispiel, die Zahlen von 1 bis 5:

SQLDatenbank: Shop

Der Schritt hat zwei Teile, verbunden durch UNION ALL:

  1. Der Anfang SELECT 1 liefert die erste Zeile.
  2. Der rekursive Teil SELECT x + 1 FROM n WHERE x < 5 nimmt die Zeilen aus der vorigen Runde und macht neue: aus 1 macht er 2, aus 2 macht er 3.

Das wiederholt sich, bis der rekursive Teil nichts mehr liefert: Bei x = 5 ist die Bedingung nicht mehr wahr. Ein solcher Schritt heißt rekursive CTE.

Ohne WHERE x < 5 würde die Abfrage nie aufhören. Jeder rekursive Teil braucht eine Bedingung, die ihn früher oder später stoppt.

Die Idee

Der Baum der Kategorien

Jetzt der Pfad. Der Anfang sind die Hauptkategorien (ohne Elternteil). Der rekursive Teil findet die Kinder von allem, was bisher gefunden wurde, und hängt ihren Namen an den Pfad:

SQLDatenbank: Shop

In der ersten Runde sind „Lebensmittel“ und „Haushalt“ da (Ebene 1). In der zweiten kommen die sechs Unterkategorien (Ebene 2), jede mit dem Pfad ihres Elternteils, „ > “ und ihrem eigenen Namen. In der dritten Runde gibt es keine Kinder mehr, und alles hört auf. Wird der Baum tiefer, erreicht dieselbe Abfrage auch die neuen Ebenen.

Probier es aus

Alles in „Lebensmittel“

Zeige Name und Preis aller Produkte in „Lebensmittel“ samt seinen Unterkategorien. Hol die Kategorienummern mit einem rekursiven Schritt, nicht von Hand. Das Feld beginnt mit dem Anfang des Schritts.

SQLDatenbank: Shop

Sieh es dir an

Die Tage ohne Verkäufe

Die Shopleitung will ein Diagramm der Verkäufe nach Tagen für Oktober 2026. Der erste Versuch:

SQLDatenbank: Shop

Fünf Zeilen. Der Oktober hat 31 Tage, und das Diagramm würde den 3. Oktober direkt mit dem 5. verbinden und verstecken, dass vom 7. bis zum 17. Oktober nichts verkauft wurde. Ein Tag ohne Bestellungen steht nicht in orders, also hat GROUP BY nichts, woraus es eine Zeile machen könnte.

Die Idee

Eine Folge von Daten

Ein rekursiver Schritt kann alle Tage selbst erzeugen. Der Anfang ist der 1. Oktober, und jede Runde fügt mit date(day, '+1 day') einen Tag hinzu:

SQLDatenbank: Shop

31 Zeilen. Jetzt werden die Verkäufe mit LEFT JOIN an die Tage gehängt, und für die Tage ohne Bestellungen setzt COALESCE eine 0:

SQLDatenbank: Shop

Alle 31 Tage sind da, auch die mit null. Die Reihenfolge beim LEFT JOIN zählt: Links stehen die Tage, von denen du alle willst, rechts die Bestellungen, die fehlen können.

Genauer, für Neugierige

PostgreSQL hat eine fertige Funktion für eine Folge: generate_series(DATE '2026-10-01', DATE '2026-10-31', INTERVAL '1 day'). In SQLite und in MySQL (ab Version 8) wird so eine Folge mit WITH RECURSIVE gemacht, wie hier.

Übung

Zwei Aufgaben

1. An wie vielen Tagen im Oktober 2026 hatte der Shop gar keine Bestellung?

Zähle die Tage im Oktober 2026 ohne eine einzige Bestellung, bis zum Ende des Monats, auch die Tage nach der letzten Bestellung (Spalte quiet_days). Das Feld hat die Folge der Tage schon.

SQLDatenbank: Shop

2. Die Website will für jedes Produkt den ganzen Pfad: „Lebensmittel > Milchprodukte > Weißkäse“.

Zeige den Namen jedes Produkts, das eine Kategorie hat, und seinen ganzen Pfad (Spalte breadcrumb), von der Hauptkategorie bis zum Produktnamen. Das Feld hat den Baum schon.

SQLDatenbank: Shop

Test

Teste dich

1. Aus welchen zwei Teilen besteht ein rekursiver Schritt?
2. Was passiert, wenn du WHERE x < 5 aus dem rekursiven Teil entfernst?
3. Eine Auswertung nach Tagen zeigt nur 5 Tage im Oktober. Warum?
4. Warum ist für den Pfad „Lebensmittel > Milchprodukte“ der rekursive Schritt besser als ein Self Join?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·