WITH RECURSIVE

Rekursive Abfragen sind ebenfalls seit PostgreSQL 8.4 verfügbar und ermöglichen erstmals die effiziente Abarbeitung von Bäumen und rekursiven Strukturen. WITH RECURSIVE ist im ANSI SQL Standard genormt und wird auch von anderen Datenbankherstellern unterstützt. Lediglich Oracle verwendet Syntaxkonstrukte, die auf dem Schlüsselwort 'CONNECT BY' beruhen, die jedoch off-Standard sind. In PostgreSQL wird nur die ANSI SQL kompatible Syntax unterstützt.

Die Handhabung von WITH RECURSIVE ist nicht immer einfach und es bedarf doch einiges am Übung, um rekursive Strukturen in SQL korrekt abzubilden. Beginnen wir daher mit einem einfachen Beispiel:

test=# WITH RECURSIVE x(n) AS 
		( SELECT 1 AS n 
		UNION ALL 
		SELECT n + 1 
			FROM 	x 
			WHERE 	n < 5) 
	SELECT * FROM x;
 n 
---
 1
 2
 3
 4
 5
(5 rows)

Unser Ziel ist es, die Zahlen von 1 bis 5 auszugeben. Da eine Addition ebenfalls als rekursive Operation angesehen werden kann, sollte das keine Probleme darstellen.

Sehen wir uns die Rekursion etwas genauer an: Der rekursive Block besteht grob gesagt aus 3 Teilen: 'SELECT 1 AS n' definiert den Startwert der Rekursion. In unserem Beispiel haben wir nur eine Zelle, die den Startwert definiert - es wäre durchaus auch möglich, dass mehr als eine Spalte verwendet wird (dazu später).

Nach dem UNION ALL finden wir die Laufbedingung der Rekursion. Bei jedem Schritt wird n um eins inkrementiert - jedoch nur so lange bis wir die Abbruchbedingung erreichen (= 'n < 5').

In unserem Beispiel verwenden wir UNION ALL, weil alle Werte in der Rekursion verwendet werden sollen. In manchen Fällen kann es vorkommen, dass es gilt, Schleifen aus einem Graphen oder dergleichen zu filtern. In solchen Fällen kann man statt UNION ALL ein einfaches UNION verwenden.

WITH RECURSIVE kann auch mit mehr als einem Parameter verwendet werden. Wenn eine Rekursion beispielsweise aus zwei Werten besteht, kann man wie folgt vorgehen:

test=# WITH RECURSIVE x(n, m) AS
                ( SELECT 1 AS n, 1 AS m
                UNION ALL
                SELECT n + 1, m + 2
                        FROM    x
                        WHERE   n < 5)
        SELECT * 
		FROM 	x
		WHERE	m < 7;
 n | m 
---+---
 1 | 1
 2 | 3
 3 | 5
(3 rows)

Beide Werte werden entsprechend inkrementiert und ausgegeben.



Subsections

Cybertec Schönig & Schönig GmbH
PostgreSQL support, training, consulting
www.postgresql-support.de