Outer Joins

Neben sogenannten Inner Joins unterstützt PostgreSQL noch sogenannte Outer Joins. Um Outer Joins ein wenig zu erläutern, beginnen wir einfach mit einem kleinen Beispiel:

test=# SELECT svnr, name, vorname 
	FROM t_person LEFT JOIN t_kind 
		ON (t_kind.eltern_svnr = t_person.svnr);
   svnr   |     name      | vorname
----------+---------------+---------
 123456   | Markus Eisner | Claudia
 123456   | Markus Eisner | Karin
 12345678 | Leo Lechner   |
 2456     | Josef Fischer |
 24567    | Anton Jelinek |
 2345     | Gaika Huber   | Bernd
 9876     | Gaika Huber   | Leopold
 9876     | Gaika Huber   | Leni
 34567    |               |
(9 rows)

Wenn wir beispielsweise alle Eltern und Kinder (falls vorhanden) listen wollen, können wir das gezeigte SQL verwenden. PostgreSQL listet alle Eltern und deren Kindern. Da nicht alle Eltern Kinder haben, bleiben einige Spalten leer. Im Fall eines Left Joins werden alle Datensätze von der 'linken' Tabelle genommen aber eben nur die entsprechenden Datensätze in der 'rechten' Tabelle ergänzt.

Right Joins bilden das Gegenstück zu Left Joins. Ändert man die Reihenfolge der Tabellen im Join erhält man somit wieder das selbe Ergebnis:

test=# SELECT svnr, name, vorname 
	FROM t_kind RIGHT JOIN t_person 
		ON (t_kind.eltern_svnr = t_person.svnr);
   svnr   |     name      | vorname
----------+---------------+---------
 123456   | Markus Eisner | Claudia
 123456   | Markus Eisner | Karin
 12345678 | Leo Lechner   |
 2456     | Josef Fischer |
 24567    | Anton Jelinek |
 2345     | Gaika Huber   | Bernd
 9876     | Gaika Huber   | Leopold
 9876     | Gaika Huber   | Leni
 34567    |               |
(9 rows)

Wenn Sie mit Outer Joins (also Left Joins und Right Joins) arbeiten, müssen Sie aufpassen, wo Sie Ihre Restriktionen hinschreiben. Fügen Sie die Bedingung in die WHERE-Clause ein, wirkt Sie auf das Ergebnis des Outer Joins - die Ergebnisse werden also möglicherweise stärker beschränkt als Ihnen das lieb ist. Im Fall unseres Beispieles könnten wir beispielsweise den Namen des Kindes auf 'Claudia' beschränken. Obwohl wir ansich alle Eltern ausgeben wollen, erhalten wir nur eine Datenzeile:

test=# SELECT svnr, name, vorname 
	FROM t_kind RIGHT JOIN t_person 
		ON (t_kind.eltern_svnr = t_person.svnr) 
	WHERE vorname = 'Claudia';
  svnr  |     name      | vorname
--------+---------------+---------
 123456 | Markus Eisner | Claudia
(1 row)

Oft glauben Programmierer, dass es sich hier um einen Bug in PostgreSQL handelt - dem ist nicht so. Es handelt sich vielmehr um das vom Standard vorgeschriebene Verhalten.

Wenn wir die Restriktion in die ON-Clause verschieben, werden Sie ein signifikant anderes Ergebnis erwarten können:

test=# SELECT svnr, name, vorname 
	FROM t_kind RIGHT JOIN t_person 
		ON (t_kind.eltern_svnr = t_person.svnr 
			AND vorname = 'Claudia');
   svnr   |     name      | vorname
----------+---------------+---------
 123456   | Markus Eisner | Claudia
 12345678 | Leo Lechner   |
 2456     | Josef Fischer |
 24567    | Anton Jelinek |
 2345     | Gaika Huber   |
 9876     | Gaika Huber   |
 34567    |               |
(7 rows)

In diesem Fall erhalten wir wieder die vollständige Liste der Eltern aber eben nur ein Kind.

Neben 'RIGHT JOIN' und 'LEFT JOIN' könnten Sie auch 'LEFT OUTER JOIN' respektive 'RIGHT OUTER JOIN' verwenden, um den gewünschten Outer Join auch syntaktisch zu untermauern. Das sieht in der Praxis dann so aus:

test=# SELECT svnr, name, vorname 
	FROM t_kind RIGHT OUTER JOIN t_person 
		ON (t_kind.eltern_svnr = t_person.svnr 
			AND vorname = 'Claudia');
   svnr   |     name      | vorname
----------+---------------+---------
 123456   | Markus Eisner | Claudia
 12345678 | Leo Lechner   |
 2456     | Josef Fischer |
 24567    | Anton Jelinek |
 2345     | Gaika Huber   |
 9876     | Gaika Huber   |
 34567    |               |
(7 rows)

Wie Sie sehen können unterscheidet sich das Ergebnis nicht vom zuvor gezeigten Listing. Oft herrscht Verwirrung über die Verwendung des Schlüsselwortes OUTER - aus diesem Grund haben wir uns zu diesem zusätzlichen Beispiel entschieden.

Klarerweise können Sie ON-Clauses auch mit WHERE-Clauses verbinden:

test=# SELECT svnr, name, vorname 
	FROM t_kind RIGHT JOIN t_person 
		ON (t_kind.eltern_svnr = t_person.svnr 
			AND vorname = 'Claudia') 
	WHERE name = 'Markus Eisner';
  svnr  |     name      | vorname
--------+---------------+---------
 123456 | Markus Eisner | Claudia
(1 row)


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