SQL Joins sind das Rückgrat relationaler Datenbanken. Sie ermöglichen es, Daten aus zwei oder mehr Tabellen basierend auf verwandten Spalten zu kombinieren. Dieser Leitfaden verwendet visuelle Diagramme und praktische Beispiele, um jeden Join-Typ klar zu erklären.
Beispieldaten: Unsere zwei Tabellen
In diesem Leitfaden verwenden wir diese zwei einfachen Tabellen:
-- employees table
+----+----------+---------------+
| id | name | department_id |
+----+----------+---------------+
| 1 | Alice | 1 |
| 2 | Bob | 2 |
| 3 | Charlie | 1 |
| 4 | Diana | NULL |
+----+----------+---------------+
-- departments table
+----+-------------+
| id | dept_name |
+----+-------------+
| 1 | Engineering |
| 2 | Marketing |
| 3 | Sales |
+----+-------------+INNER JOIN
Gibt nur Zeilen zurück, die in beiden Tabellen übereinstimmende Werte haben.
Table A Table B
+---------+ +---------+
| | | |
| +----+-----+----+ |
| | INNER JOIN | |
| +----+-----+----+ |
| | | |
+---------+ +---------+SELECT e.name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;Ergebnis:
+----------+-------------+
| name | dept_name |
+----------+-------------+
| Alice | Engineering |
| Bob | Marketing |
| Charlie | Engineering |
+----------+-------------+
-- Diana excluded (department_id is NULL)
-- Sales excluded (no employee in Sales)Verwenden Sie es, wenn Sie nur Datensätze benötigen, die in beiden Tabellen existieren.
LEFT JOIN
Gibt alle Zeilen der linken Tabelle und übereinstimmende Zeilen der rechten Tabelle zurück.
Table A Table B
+---------+ +---------+
|XXXXXXXXX| | |
|XXXX+----+-----+----+ |
|XXXX| LEFT JOIN XXXX| |
|XXXX+----+-----+----+ |
|XXXXXXXXX| | |
+---------+ +---------+
(all of A + matching B)SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;Ergebnis:
+----------+-------------+
| name | dept_name |
+----------+-------------+
| Alice | Engineering |
| Bob | Marketing |
| Charlie | Engineering |
| Diana | NULL |
+----------+-------------+
-- Diana included with NULL dept_nameVerwenden Sie es, wenn Sie alle Datensätze der linken Tabelle benötigen.
RIGHT JOIN
Gibt alle Zeilen der rechten Tabelle und übereinstimmende Zeilen der linken Tabelle zurück.
Table A Table B
+---------+ +---------+
| | |XXXXXXXXX|
| +----+-----+XXXX+XXXX|
| |XXXX RIGHT JOINXXXX|
| +----+-----+XXXX+XXXX|
| | |XXXXXXXXX|
+---------+ +---------+
(matching A + all of B)SELECT e.name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.id;Ergebnis:
+----------+-------------+
| name | dept_name |
+----------+-------------+
| Alice | Engineering |
| Charlie | Engineering |
| Bob | Marketing |
| NULL | Sales |
+----------+-------------+
-- Sales included with NULL nameVerwenden Sie es, wenn Sie alle Datensätze der rechten Tabelle benötigen.
FULL OUTER JOIN
Gibt alle Zeilen beider Tabellen zurück. Fehlende Werte werden mit NULL gefüllt.
Table A Table B
+---------+ +---------+
|XXXXXXXXX| |XXXXXXXXX|
|XXXX+----+-----+XXXX+XXXX|
|XXXX|FULL OUTER JOINXXXX|
|XXXX+----+-----+XXXX+XXXX|
|XXXXXXXXX| |XXXXXXXXX|
+---------+ +---------+
(everything from both)SELECT e.name, d.dept_name
FROM employees e
FULL OUTER JOIN departments d ON e.department_id = d.id;Ergebnis:
+----------+-------------+
| name | dept_name |
+----------+-------------+
| Alice | Engineering |
| Bob | Marketing |
| Charlie | Engineering |
| Diana | NULL |
| NULL | Sales |
+----------+-------------+Verwenden Sie es, wenn Sie alle Datensätze beider Tabellen benötigen.
CROSS JOIN
Gibt das kartesische Produkt beider Tabellen zurück. Keine ON-Klausel nötig.
SELECT e.name, d.dept_name
FROM employees e
CROSS JOIN departments d;
-- Returns 4 × 3 = 12 rowsErgebnis:
+----------+-------------+
| name | dept_name |
+----------+-------------+
| Alice | Engineering |
| Alice | Marketing |
| Alice | Sales |
| Bob | Engineering |
| Bob | Marketing |
| Bob | Sales |
| Charlie | Engineering |
| Charlie | Marketing |
| Charlie | Sales |
| Diana | Engineering |
| Diana | Marketing |
| Diana | Sales |
+----------+-------------+Für Kombinationen, Testdaten oder Kalenderraster.
Self JOIN
Eine Tabelle wird mit sich selbst verknüpft. Nützlich für hierarchische Daten.
-- employees_v2 with manager_id column
+----+---------+------------+
| id | name | manager_id |
+----+---------+------------+
| 1 | Alice | NULL |
| 2 | Bob | 1 |
| 3 | Charlie | 1 |
| 4 | Diana | 2 |
+----+---------+------------+
SELECT
e.name AS employee,
m.name AS manager
FROM employees_v2 e
LEFT JOIN employees_v2 m ON e.manager_id = m.id;Ergebnis:
+----------+---------+
| employee | manager |
+----------+---------+
| Alice | NULL |
| Bob | Alice |
| Charlie | Alice |
| Diana | Bob |
+----------+---------+Für Mitarbeiter-Manager-Beziehungen oder Zeilenvergleiche.
Welchen Join verwenden? Kurzreferenz
| Join-Typ | Gibt zurück | Anwendungsfall |
|---|---|---|
| INNER JOIN | A ∩ B | Only matching data |
| LEFT JOIN | A + (A ∩ B) | All left + matching right |
| RIGHT JOIN | (A ∩ B) + B | All right + matching left |
| FULL OUTER JOIN | A ∪ B | Everything from both |
| CROSS JOIN | A × B | Generate all combinations |
| Self JOIN | Depends on join type | Hierarchical / self-referencing data |
Performance-Tipps
- Erstellen Sie immer Indizes für JOIN-Spalten.
- Vermeiden Sie SELECT * in Produktionsabfragen.
- Platzieren Sie die kleinere Tabelle zuerst in FROM.
- Verwenden Sie EXPLAIN ANALYZE zur Überprüfung.
- Bevorzugen Sie EXISTS gegenüber IN bei korrelierten Unterabfragen.
- Vermeiden Sie Joins auf Ausdrücken oder Funktionen.
-- Create index on JOIN column
CREATE INDEX idx_emp_dept ON employees(department_id);
-- Use EXPLAIN to check query plan
EXPLAIN ANALYZE
SELECT e.name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;Häufige Fehler
| Fehler | Problem | Lösung |
|---|---|---|
| Using SELECT * | Returns unnecessary columns, wastes bandwidth | Select only needed columns |
| Missing index on JOIN column | Full table scan, extremely slow | CREATE INDEX |
| NULL comparison trap | NULL = NULL evaluates to FALSE | Use IS NULL or COALESCE |
| Accidental Cartesian product | Missing ON condition, row explosion | Always verify ON clause |
| Filtering OUTER JOIN in WHERE | WHERE filter turns LEFT JOIN into INNER JOIN | Put conditions in ON clause |
| Unnecessary DISTINCT | Hides incorrect JOIN logic | Fix JOIN condition, don't add DISTINCT |
| Joining on functions | Index unusable, forces full scan | Store normalized data or use computed columns |
-- ❌ Wrong: WHERE turns LEFT JOIN into INNER JOIN
SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id
WHERE d.dept_name = 'Engineering'; -- filters out NULLs!
-- ✅ Correct: Put condition in ON clause
SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d
ON e.department_id = d.id
AND d.dept_name = 'Engineering'; -- preserves NULLsHäufig gestellte Fragen
Was ist der Unterschied zwischen INNER JOIN und OUTER JOIN?
INNER JOIN gibt nur übereinstimmende Zeilen zurück. OUTER JOIN enthält auch nicht übereinstimmende Zeilen mit NULL.
Kann man mehr als zwei Tabellen joinen?
Ja. Sie können mehrere JOINs verketten.
Was passiert ohne ON-Klausel?
In den meisten SQL-Dialekten ergibt das einen Syntaxfehler.
Sind LEFT JOIN und LEFT OUTER JOIN identisch?
Ja. Das OUTER-Schlüsselwort ist optional.
Welcher Join ist am schnellsten?
INNER JOIN ist in der Regel am schnellsten. Die tatsächliche Performance hängt von Indizes und dem Optimierer ab.
Was ist ein NATURAL JOIN?
Ein automatischer Join auf gleichnamigen Spalten. In Produktion nicht empfohlen.